From: Tony Tkacik Date: Mon, 17 Feb 2014 16:28:11 +0000 (+0000) Subject: Merge "Add support for multiple choice case statements within one augument in config... X-Git-Tag: autorelease-tag-v20140601202136_82eb3f9~427 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=commitdiff_plain;h=2e7347fdc0eb7734ff59a4f902227a93ab6afece;hp=bb14f3f60be546ba6dc99f6b87d6cbce9003c5e3;p=controller.git Merge "Add support for multiple choice case statements within one augument in config yang files" --- diff --git a/opendaylight/appauth/pom.xml b/opendaylight/appauth/pom.xml index 934fdfae80..30879c6565 100644 --- a/opendaylight/appauth/pom.xml +++ b/opendaylight/appauth/pom.xml @@ -27,6 +27,7 @@ + org.opendaylight.controller.configuration, org.opendaylight.controller.containermanager, org.opendaylight.controller.sal.authorization, org.opendaylight.controller.sal.utils, @@ -47,6 +48,10 @@ + + org.opendaylight.controller + configuration + org.opendaylight.controller sal diff --git a/opendaylight/appauth/src/main/java/org/opendaylight/controller/appauth/authorization/Authorization.java b/opendaylight/appauth/src/main/java/org/opendaylight/controller/appauth/authorization/Authorization.java index 1992f59711..b70a79b4ae 100644 --- a/opendaylight/appauth/src/main/java/org/opendaylight/controller/appauth/authorization/Authorization.java +++ b/opendaylight/appauth/src/main/java/org/opendaylight/controller/appauth/authorization/Authorization.java @@ -16,6 +16,7 @@ import java.util.Map.Entry; import java.util.Set; import java.util.concurrent.ConcurrentMap; +import org.opendaylight.controller.configuration.ConfigurationObject; import org.opendaylight.controller.containermanager.IContainerAuthorization; import org.opendaylight.controller.sal.authorization.AppRoleLevel; import org.opendaylight.controller.sal.authorization.IResourceAuthorization; @@ -36,7 +37,7 @@ import org.slf4j.LoggerFactory; */ public abstract class Authorization implements IResourceAuthorization { private static final Logger logger = LoggerFactory.getLogger(Authorization.class); - private static final String namesRegex = "^[a-zA-Z0-9]+[{\\.|\\_|\\-}[a-zA-Z0-9]]*$"; + private static final String namesRegex = ConfigurationObject.getRegularExpression(); /* * The configured resource groups */ diff --git a/opendaylight/arphandler/src/main/java/org/opendaylight/controller/arphandler/ARPReply.java b/opendaylight/arphandler/src/main/java/org/opendaylight/controller/arphandler/ARPReply.java index e4388c598f..a6ee60f65d 100644 --- a/opendaylight/arphandler/src/main/java/org/opendaylight/controller/arphandler/ARPReply.java +++ b/opendaylight/arphandler/src/main/java/org/opendaylight/controller/arphandler/ARPReply.java @@ -18,7 +18,7 @@ import org.opendaylight.controller.sal.utils.HexEncode; * 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; diff --git a/opendaylight/arphandler/src/main/java/org/opendaylight/controller/arphandler/ARPRequest.java b/opendaylight/arphandler/src/main/java/org/opendaylight/controller/arphandler/ARPRequest.java index 1b125ddeb2..051635ad53 100644 --- a/opendaylight/arphandler/src/main/java/org/opendaylight/controller/arphandler/ARPRequest.java +++ b/opendaylight/arphandler/src/main/java/org/opendaylight/controller/arphandler/ARPRequest.java @@ -19,6 +19,7 @@ import org.opendaylight.controller.switchmanager.Subnet; * specified host */ public class ARPRequest extends ARPEvent { + private static final long serialVersionUID = 1L; private final Subnet subnet; private final HostNodeConnector host; diff --git a/opendaylight/commons/opendaylight/pom.xml b/opendaylight/commons/opendaylight/pom.xml index 9d4f838992..93845a356d 100644 --- a/opendaylight/commons/opendaylight/pom.xml +++ b/opendaylight/commons/opendaylight/pom.xml @@ -4,7 +4,6 @@ 3.0 - org.opendaylight.controller commons.opendaylight 1.4.2-SNAPSHOT pom @@ -57,11 +56,11 @@ -Xmx1024m -XX:MaxPermSize=256m 14.0.1 5.0.0 - 2010.09.24.3 - 2010.09.24.3 - 2013.10.21.1 - 2013.08.27.3 - 2013.09.07.3 + 2010.09.24.4-SNAPSHOT + 2010.09.24.4-SNAPSHOT + 2013.10.21.2-SNAPSHOT + 2013.08.27.4-SNAPSHOT + 2013.09.07.4-SNAPSHOT 3.17.1-GA 2.3.2 3.1 @@ -91,7 +90,7 @@ 0.0.3-SNAPSHOT 0.1.2-SNAPSHOT 0.5.2-SNAPSHOT - 0.4.1-SNAPSHOT + 0.5.0-SNAPSHOT 4.0.10.Final 2.4 0.4.2-SNAPSHOT @@ -722,6 +721,11 @@ netty-common ${netty.version} + + io.netty + netty-codec-http + ${netty.version} + @@ -754,6 +758,12 @@ yang-model-api ${yangtools.version} + + org.opendaylight.yangtools + yang-model-util + ${yangtools.version} + + org.opendaylight.controller hosttracker @@ -789,11 +799,6 @@ clustering.stub ${clustering.stub.version} - - org.opendaylight.controller - configuration - ${controller.version} - org.opendaylight.controller configuration.implementation @@ -1432,7 +1437,6 @@ netty-timer-config ${config.version} - org.opendaylight.controller configuration diff --git a/opendaylight/commons/protocol-framework/pom.xml b/opendaylight/commons/protocol-framework/pom.xml index b162b9c400..a03518235b 100644 --- a/opendaylight/commons/protocol-framework/pom.xml +++ b/opendaylight/commons/protocol-framework/pom.xml @@ -17,7 +17,7 @@ protocol-framework - 0.4.1-SNAPSHOT + 0.5.0-SNAPSHOT Common protocol framework bundle ${project.artifactId} diff --git a/opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/DeserializerException.java b/opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/DeserializerException.java deleted file mode 100644 index 608e949085..0000000000 --- a/opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/DeserializerException.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v1.0 which accompanies this distribution, - * and is available at http://www.eclipse.org/legal/epl-v10.html - */ -package org.opendaylight.protocol.framework; - -/** - * Used when something occurs during parsing bytes to java objects. - * - * @deprecated This exception no longer carries any special meaning. Users - * are advised to stop using it and define their own replacement. - */ -@Deprecated -public class DeserializerException extends Exception { - - private static final long serialVersionUID = -2247000673438452870L; - - /** - * Creates a deserializer exception. - * @param err string - */ - public DeserializerException(final String err) { - super(err); - } - - /** - * Creates a deserializer exception. - * @param err string - * @param e underlying exception - */ - public DeserializerException(final String err, final Throwable e) { - super(err, e); - } -} diff --git a/opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/DocumentedException.java b/opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/DocumentedException.java deleted file mode 100644 index 5e5f29eafe..0000000000 --- a/opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/DocumentedException.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v1.0 which accompanies this distribution, - * and is available at http://www.eclipse.org/legal/epl-v10.html - */ -package org.opendaylight.protocol.framework; - -/** - * Documented exception occurrs when an error is thrown that is documented - * in any RFC or draft for the specific protocol. - * - * @deprecated This exception no longer carries any special meaning. Users - * are advised to stop using it and define their own replacement. - */ -@Deprecated -public class DocumentedException extends Exception { - - private static final long serialVersionUID = -3727963789710833704L; - - /** - * Creates a documented exception - * @param message string - */ - public DocumentedException(final String message) { - super(message); - } - - /** - * Creates a documented exception - * @param err string - * @param cause the cause (which is saved for later retrieval by the - * Throwable.getCause() method). (A null value is permitted, and indicates - * that the cause is nonexistent or unknown.) - */ - public DocumentedException(final String err, final Exception cause) { - super(err, cause); - } -} diff --git a/opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/ProtocolHandlerFactory.java b/opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/ProtocolHandlerFactory.java deleted file mode 100644 index 5c1377d9f5..0000000000 --- a/opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/ProtocolHandlerFactory.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v1.0 which accompanies this distribution, - * and is available at http://www.eclipse.org/legal/epl-v10.html - */ -package org.opendaylight.protocol.framework; - -import io.netty.channel.ChannelHandler; - -import com.google.common.base.Preconditions; - -/** - * @deprecated This is an adaptor class for turning ProtocolMessageFactory into - * Netty encoder/decoder. Use Netty-provided classes directly, by subclassing - * {@link io.netty.handler.codec.ByteToMessageDecoder} or similar instead. - */ -@Deprecated -public class ProtocolHandlerFactory { - private final ProtocolMessageEncoder encoder; - protected final ProtocolMessageFactory msgFactory; - - public ProtocolHandlerFactory(final ProtocolMessageFactory msgFactory) { - this.msgFactory = Preconditions.checkNotNull(msgFactory); - this.encoder = new ProtocolMessageEncoder(msgFactory); - } - - public ChannelHandler[] getEncoders() { - return new ChannelHandler[] { this.encoder }; - } - - public ChannelHandler[] getDecoders() { - return new ChannelHandler[] { new ProtocolMessageDecoder(this.msgFactory) }; - } -} diff --git a/opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/ProtocolMessageDecoder.java b/opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/ProtocolMessageDecoder.java deleted file mode 100644 index 725e0a21a7..0000000000 --- a/opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/ProtocolMessageDecoder.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v1.0 which accompanies this distribution, - * and is available at http://www.eclipse.org/legal/epl-v10.html - */ -package org.opendaylight.protocol.framework; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufUtil; -import io.netty.channel.ChannelHandlerContext; -import io.netty.handler.codec.ByteToMessageDecoder; - -import java.util.List; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.google.common.base.Preconditions; - -/** - * @deprecated This is an adaptor class for turning ProtocolMessageFactory into Netty decoder. Use Netty-provided - * classes directly, by subclassing {@link io.netty.handler.codec.ByteToMessageDecoder} or similar instead. - */ -@Deprecated -public final class ProtocolMessageDecoder extends ByteToMessageDecoder { - - private static final Logger LOG = LoggerFactory.getLogger(ProtocolMessageDecoder.class); - - private final ProtocolMessageFactory factory; - - public ProtocolMessageDecoder(final ProtocolMessageFactory factory) { - this.factory = Preconditions.checkNotNull(factory); - } - - @Override - protected void decode(final ChannelHandlerContext ctx, final ByteBuf in, final List out) throws Exception { - if (in.readableBytes() == 0) { - LOG.debug("No more content in incoming buffer."); - return; - } - in.markReaderIndex(); - try { - LOG.trace("Received to decode: {}", ByteBufUtil.hexDump(in)); - final byte[] bytes = new byte[in.readableBytes()]; - in.readBytes(bytes); - out.add(this.factory.parse(bytes)); - } catch (DeserializerException | DocumentedException e) { - LOG.debug("Failed to decode protocol message", e); - this.exceptionCaught(ctx, e); - } - in.discardReadBytes(); - } -} diff --git a/opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/ProtocolMessageEncoder.java b/opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/ProtocolMessageEncoder.java deleted file mode 100644 index 66378e75d6..0000000000 --- a/opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/ProtocolMessageEncoder.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v1.0 which accompanies this distribution, - * and is available at http://www.eclipse.org/legal/epl-v10.html - */ -package org.opendaylight.protocol.framework; - -import io.netty.buffer.ByteBuf; -import io.netty.channel.ChannelHandler.Sharable; -import io.netty.channel.ChannelHandlerContext; -import io.netty.handler.codec.MessageToByteEncoder; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * @deprecated This is an adaptor class for turning ProtocolMessageFactory into Netty encoder. Use Netty-provided - * classes directly, by subclassing {@link io.netty.handler.codec.MessageToByteDecoder} or similar instead. - */ -@Deprecated -@Sharable -public final class ProtocolMessageEncoder extends MessageToByteEncoder { - - private static final Logger LOG = LoggerFactory.getLogger(ProtocolMessageEncoder.class); - - private final ProtocolMessageFactory factory; - - public ProtocolMessageEncoder(final ProtocolMessageFactory factory) { - this.factory = factory; - } - - @Override - protected void encode(final ChannelHandlerContext ctx, final Object msg, final ByteBuf out) throws Exception { - LOG.debug("Sent to encode : {}", msg); - final byte[] bytes = this.factory.put((T) msg); - out.writeBytes(bytes); - } -} diff --git a/opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/ProtocolMessageFactory.java b/opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/ProtocolMessageFactory.java deleted file mode 100644 index 9b89dc3592..0000000000 --- a/opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/ProtocolMessageFactory.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v1.0 which accompanies this distribution, - * and is available at http://www.eclipse.org/legal/epl-v10.html - */ -package org.opendaylight.protocol.framework; - - -/** - * Interface for factory for parsing and serializing protocol specific messages. Needs to be implemented by a protocol - * specific message factory. The methods put/parse should delegate parsing to specific message parsers, e.g. - * OpenMessageParser etc. - * - * @param type of messages created by this factory - * - * @deprecated Interact with Netty 4.0 directly, by subclassing {@link io.netty.handler.codec.ByteToMessageCodec} or - * similar. - */ -@Deprecated -public interface ProtocolMessageFactory { - - /** - * Parses message from byte array. Requires specific protocol message header object to parse the header. - * - * @param bytes byte array from which the message will be parsed - * @return List of specific protocol messages - * @throws DeserializerException if some parsing error occurs - * @throws DocumentedException if some documented error occurs - */ - T parse(byte[] bytes) throws DeserializerException, DocumentedException; - - /** - * Serializes protocol specific message to byte array. - * - * @param msg message to be serialized. - * @return byte array resulting message - */ - byte[] put(T msg); -} diff --git a/opendaylight/commons/protocol-framework/src/test/java/org/opendaylight/protocol/framework/ComplementaryTest.java b/opendaylight/commons/protocol-framework/src/test/java/org/opendaylight/protocol/framework/ComplementaryTest.java deleted file mode 100644 index 80e6ad9cde..0000000000 --- a/opendaylight/commons/protocol-framework/src/test/java/org/opendaylight/protocol/framework/ComplementaryTest.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v1.0 which accompanies this distribution, - * and is available at http://www.eclipse.org/legal/epl-v10.html - */ -package org.opendaylight.protocol.framework; - -import static org.junit.Assert.assertEquals; - -import org.junit.Test; - -@Deprecated -public class ComplementaryTest { - - @Test - public void testExceptions() { - final DeserializerException de = new DeserializerException("some error"); - final DocumentedException ee = new DocumentedException("some error"); - - assertEquals(de.getMessage(), ee.getMessage()); - } -} diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/TransactionIdentifier.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/TransactionIdentifier.java index 5ab09bea11..28bd613648 100644 --- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/TransactionIdentifier.java +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/TransactionIdentifier.java @@ -10,7 +10,7 @@ package org.opendaylight.controller.config.manager.impl; import org.opendaylight.yangtools.concepts.Identifier; public class TransactionIdentifier implements Identifier { - + private static final long serialVersionUID = 1L; private final String name; public TransactionIdentifier(String name) { diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/BindingIndependentMappingServiceTracker.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/BindingIndependentMappingServiceTracker.java index 06a5826086..16a0605cd4 100644 --- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/BindingIndependentMappingServiceTracker.java +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/BindingIndependentMappingServiceTracker.java @@ -15,11 +15,6 @@ import org.osgi.util.tracker.ServiceTrackerCustomizer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -/** - * Every time factory is added or removed, blank transaction is triggered to handle - * {@link org.opendaylight.controller.config.spi.ModuleFactory#getDefaultModules(org.opendaylight.controller.config.api.DependencyResolverFactory, org.osgi.framework.BundleContext)} - * functionality. - */ public class BindingIndependentMappingServiceTracker implements ServiceTrackerCustomizer { private static final Logger logger = LoggerFactory.getLogger(BindingIndependentMappingServiceTracker.class); @@ -48,7 +43,7 @@ public class BindingIndependentMappingServiceTracker implements ServiceTrackerCu BindingIndependentMappingService service = ctx.getService(moduleFactoryServiceReference); this.service = service; CodecRegistry codecRegistry = service.getCodecRegistry(); - logger.warn("Codec registry acquired {}", codecRegistry); + logger.debug("Codec registry acquired {}", codecRegistry); activator.initConfigManager(ctx, codecRegistry); return service; } @@ -59,7 +54,7 @@ public class BindingIndependentMappingServiceTracker implements ServiceTrackerCu } @Override - public void removedService(ServiceReference moduleFactoryServiceReference, BindingIndependentMappingService o) { + public void removedService(ServiceReference moduleFactoryServiceReference, BindingIndependentMappingService o) { // TODO crash } } diff --git a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/AbstractConfigTest.java b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/AbstractConfigTest.java index d9bbeb4a2c..001af7525b 100644 --- a/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/AbstractConfigTest.java +++ b/opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/AbstractConfigTest.java @@ -213,7 +213,6 @@ public abstract class AbstractConfigTest extends return mock(CodecRegistry.class); } - public static interface BundleContextServiceRegistrationHandler { void handleServiceRegistration(Object serviceInstance); diff --git a/opendaylight/config/config-module-archetype/pom.xml b/opendaylight/config/config-module-archetype/pom.xml new file mode 100644 index 0000000000..42c9105c05 --- /dev/null +++ b/opendaylight/config/config-module-archetype/pom.xml @@ -0,0 +1,15 @@ + + + 4.0.0 + + org.opendaylight.controller + config-subsystem + 0.2.4-SNAPSHOT + + + config-module-archetype + config-module-archetype + Archetype for new module managed by configuration subsystem + + diff --git a/opendaylight/config/config-module-archetype/src/main/resources/META-INF/maven/archetype-metadata.xml b/opendaylight/config/config-module-archetype/src/main/resources/META-INF/maven/archetype-metadata.xml new file mode 100644 index 0000000000..fc30b4d2c3 --- /dev/null +++ b/opendaylight/config/config-module-archetype/src/main/resources/META-INF/maven/archetype-metadata.xml @@ -0,0 +1,46 @@ + + config-module-archetype + + true + + + + + + + + impl + + + 2013-04-05 + + + 0.2.4-SNAPSHOT + + + 0.6.2-SNAPSHOT + + + 2014-01-31 + + + java.lang.AutoCloseable + + + 2.4.0 + + + urn:opendaylight:params:xml:ns:yang:controller + + + org.opendaylight.controller.config.yang + + + + + + + src/main/yang + + + diff --git a/opendaylight/config/config-module-archetype/src/main/resources/archetype-resources/pom.xml b/opendaylight/config/config-module-archetype/src/main/resources/archetype-resources/pom.xml new file mode 100644 index 0000000000..d1c371d618 --- /dev/null +++ b/opendaylight/config/config-module-archetype/src/main/resources/archetype-resources/pom.xml @@ -0,0 +1,104 @@ + + 4.0.0 + + ${groupId} + ${artifactId} + ${version} + bundle + + + ${project.build.directory}/generated-sources/config + ${config-api-version} + ${maven-bundle-plugin-version} + + + + + org.opendaylight.controller + config-api + ${config.version} + + + + + + + org.opendaylight.yangtools + yang-maven-plugin + ${yang-maven-plugin-version} + + + config + + generate-sources + + + + + + org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator + + ${jmxGeneratorPath} + + + ${yang-namespace-mapping-from}==${yang-namespace-mapping-to} + + + + + true + + + + + + org.opendaylight.controller + yang-jmx-generator-plugin + ${config.version} + + + + + + org.codehaus.mojo + build-helper-maven-plugin + 1.8 + + + add-source + generate-sources + + add-source + + + + ${jmxGeneratorPath} + + + + + + + + org.apache.felix + maven-bundle-plugin + ${maven.bundle.version} + true + + + ${project.groupId}.${project.artifactId} + + ${yang-namespace-mapping-to}.${module-name}, + + + * + + + + + + + + + diff --git a/opendaylight/config/config-module-archetype/src/main/resources/archetype-resources/src/main/yang/__module-name__-impl.yang b/opendaylight/config/config-module-archetype/src/main/resources/archetype-resources/src/main/yang/__module-name__-impl.yang new file mode 100644 index 0000000000..8c1dab1495 --- /dev/null +++ b/opendaylight/config/config-module-archetype/src/main/resources/archetype-resources/src/main/yang/__module-name__-impl.yang @@ -0,0 +1,54 @@ +// vi: set smarttab et sw=4 tabstop=4: +module ${module-name}-${module-implementation-name} { + + yang-version 1; + namespace "urn:opendaylight:params:xml:ns:yang:controller:config:${module-name}:${module-implementation-name}"; + prefix "${module-name}-${module-implementation-name}"; + + import config { prefix config; revision-date ${config-api-yang-revision}; } + import ${module-name} { prefix ${module-name}; revision-date ${revision}; } + + description + "This module contains the base YANG definitions for + ${module-name} ${module-implementation-name} implementation."; + + revision "${revision}" { + description + "Initial revision."; + } + + // This is the definition of a service implementation + identity ${module-name}-${module-implementation-name} { + base config:module-type; + config:provided-service ${module-name}:${module-name}; + config:java-name-prefix ${module-name-java-prefix}; + } + + augment "/config:modules/config:module/config:configuration" { + case ${module-name}-${module-implementation-name} { + when "/config:modules/config:module/config:type = '${module-name}-${module-implementation-name}'"; + + leaf simple-attribute { + type uint32; + } + + container dto-attribute { + leaf inner-attribute { + type string; + } + } + + // Dependency attribute demonstration, the config:required-identity points to a service type + // In this case it is the same service type as this implementation provides: ${module-name} + container dependency-attribute { + uses config:service-ref { + refine type { + mandatory false; + config:required-identity ${module-name}:${module-name}; + } + } + } + + } + } +} \ No newline at end of file diff --git a/opendaylight/config/config-module-archetype/src/main/resources/archetype-resources/src/main/yang/__module-name__.yang b/opendaylight/config/config-module-archetype/src/main/resources/archetype-resources/src/main/yang/__module-name__.yang new file mode 100644 index 0000000000..2afc91e8e3 --- /dev/null +++ b/opendaylight/config/config-module-archetype/src/main/resources/archetype-resources/src/main/yang/__module-name__.yang @@ -0,0 +1,27 @@ +// vi: set smarttab et sw=4 tabstop=4: +module ${module-name} { + + yang-version 1; + namespace "urn:opendaylight:params:xml:ns:yang:controller:config:${module-name}"; + prefix "${module-name}"; + + import config { prefix config; revision-date ${config-api-yang-revision}; } + + description + "This module contains the base YANG definitions for + ${module-name} services."; + + revision "${revision}" { + description + "Initial revision."; + } + + // This is the definition of a service + identity ${module-name} { + + base "config:service-type"; + + // TODO modify the java class + config:java-class " ${service-java-class}"; + } +} \ No newline at end of file diff --git a/opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/model/PersistException.java b/opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/model/PersistException.java index 29d623274c..a0ccdb8e2e 100644 --- a/opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/model/PersistException.java +++ b/opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/model/PersistException.java @@ -8,6 +8,7 @@ package org.opendaylight.controller.config.persist.storage.file.xml.model; final class PersistException extends RuntimeException { + private static final long serialVersionUID = 1L; public PersistException(String s, Exception e) { super(s, e); diff --git a/opendaylight/config/config-util/src/test/java/org/opendaylight/controller/config/util/ConfigRegistryClientsTest.java b/opendaylight/config/config-util/src/test/java/org/opendaylight/controller/config/util/ConfigRegistryClientsTest.java index 4c99c7770a..13043458c0 100644 --- a/opendaylight/config/config-util/src/test/java/org/opendaylight/controller/config/util/ConfigRegistryClientsTest.java +++ b/opendaylight/config/config-util/src/test/java/org/opendaylight/controller/config/util/ConfigRegistryClientsTest.java @@ -47,7 +47,7 @@ public class ConfigRegistryClientsTest { @Test public void testLookupRuntimeBeans() throws Exception { Set 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 lookupRuntimeBeans(ConfigRegistryClient client) @@ -67,13 +67,13 @@ public class ConfigRegistryClientsTest { 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, diff --git a/opendaylight/config/pom.xml b/opendaylight/config/pom.xml index dbf8654d6e..80621a4d44 100644 --- a/opendaylight/config/pom.xml +++ b/opendaylight/config/pom.xml @@ -1,6 +1,5 @@ - - + 4.0.0 @@ -44,6 +43,7 @@ yang-test-plugin shutdown-api shutdown-impl + config-module-archetype @@ -410,7 +410,7 @@ - + @@ -420,4 +420,4 @@ - + \ No newline at end of file diff --git a/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/util/NameConflictException.java b/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/util/NameConflictException.java index 2ae70562cf..ec2d985339 100644 --- a/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/util/NameConflictException.java +++ b/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/util/NameConflictException.java @@ -10,7 +10,7 @@ package org.opendaylight.controller.config.yangjmxgenerator.plugin.util; import org.opendaylight.yangtools.yang.common.QName; public class NameConflictException extends RuntimeException { - + private static final long serialVersionUID = 1L; private static final String messageBlueprint = "Name conflict for name: %s, first defined in: %s, then defined in: %s"; private final String conflictingName; private final QName secondParentQName; diff --git a/opendaylight/config/yang-jmx-generator/src/test/java/org/opendaylight/controller/config/yangjmxgenerator/SchemaContextTest.java b/opendaylight/config/yang-jmx-generator/src/test/java/org/opendaylight/controller/config/yangjmxgenerator/SchemaContextTest.java index 14ec7e0fdc..1837bac266 100644 --- a/opendaylight/config/yang-jmx-generator/src/test/java/org/opendaylight/controller/config/yangjmxgenerator/SchemaContextTest.java +++ b/opendaylight/config/yang-jmx-generator/src/test/java/org/opendaylight/controller/config/yangjmxgenerator/SchemaContextTest.java @@ -100,12 +100,15 @@ public class SchemaContextTest extends AbstractYangTest { @Test public void testReadingIdentities_threadsJavaModule() { - Map> expectedIdentitiesToBases = new HashMap(){{ + Map> expectedIdentitiesToBases = new HashMap>(){ + private static final long serialVersionUID = 1L; + + { put(ModuleMXBeanEntryTest.EVENTBUS_MXB_NAME, Optional.of(MODULE_TYPE_Q_NAME)); put(ModuleMXBeanEntryTest.ASYNC_EVENTBUS_MXB_NAME, Optional.of(MODULE_TYPE_Q_NAME)); put(ModuleMXBeanEntryTest.THREADFACTORY_NAMING_MXB_NAME, Optional.of(MODULE_TYPE_Q_NAME)); put(ModuleMXBeanEntryTest.THREADPOOL_DYNAMIC_MXB_NAME, Optional.of(MODULE_TYPE_Q_NAME)); - put("thread-rpc-context", Optional.absent()); + put("thread-rpc-context", Optional.absent()); put(ModuleMXBeanEntryTest.THREADPOOL_REGISTRY_IMPL_NAME, Optional.of(MODULE_TYPE_Q_NAME)); }}; diff --git a/opendaylight/config/yang-test/pom.xml b/opendaylight/config/yang-test/pom.xml index 8e40260dbf..9c6e98e571 100644 --- a/opendaylight/config/yang-test/pom.xml +++ b/opendaylight/config/yang-test/pom.xml @@ -59,7 +59,49 @@ + + + + + + org.eclipse.m2e + lifecycle-mapping + 1.0.0 + + + + + + + org.opendaylight.controller + + + yang-test-plugin + + + [0.2.3,) + + + + delete-sources + + + process-sources + + + + + + + + + + + + + + org.opendaylight.yangtools diff --git a/opendaylight/configuration/api/src/main/java/org/opendaylight/controller/configuration/ConfigurationObject.java b/opendaylight/configuration/api/src/main/java/org/opendaylight/controller/configuration/ConfigurationObject.java index 34542de896..7151e561b1 100644 --- a/opendaylight/configuration/api/src/main/java/org/opendaylight/controller/configuration/ConfigurationObject.java +++ b/opendaylight/configuration/api/src/main/java/org/opendaylight/controller/configuration/ConfigurationObject.java @@ -12,7 +12,7 @@ import java.io.Serializable; public abstract class ConfigurationObject implements Serializable { private static final long serialVersionUID = 1L; - private static final String DEFAULT_REGEX = "^[\\w-\\+\\*\\/\\.\\(\\)\\[\\]\\@]{1,256}$"; + private static final String DEFAULT_REGEX = "^[\\w-=\\+\\*\\.\\(\\)\\[\\]\\@\\|\\:]{1,256}$"; private static final String REGEX_PROP_NAME = "resourceNameRegularExpression"; private static String regex; @@ -31,7 +31,7 @@ public abstract class ConfigurationObject implements Serializable { * resource name regular expression, false otherwise */ protected boolean isValidResourceName(String name) { - return (name != null) ? name.matches(regex) : false; + return name != null && name.matches(regex); } /** diff --git a/opendaylight/configuration/api/src/main/java/org/opendaylight/controller/configuration/IConfigurationContainerService.java b/opendaylight/configuration/api/src/main/java/org/opendaylight/controller/configuration/IConfigurationContainerService.java index 2123f6b9eb..ee571b83e1 100644 --- a/opendaylight/configuration/api/src/main/java/org/opendaylight/controller/configuration/IConfigurationContainerService.java +++ b/opendaylight/configuration/api/src/main/java/org/opendaylight/controller/configuration/IConfigurationContainerService.java @@ -13,4 +13,12 @@ package org.opendaylight.controller.configuration; * 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(); } diff --git a/opendaylight/configuration/implementation/src/main/java/org/opendaylight/controller/configuration/internal/ConfigurationService.java b/opendaylight/configuration/implementation/src/main/java/org/opendaylight/controller/configuration/internal/ConfigurationService.java index e4d55d11fb..4c0f3a2da5 100644 --- a/opendaylight/configuration/implementation/src/main/java/org/opendaylight/controller/configuration/internal/ConfigurationService.java +++ b/opendaylight/configuration/implementation/src/main/java/org/opendaylight/controller/configuration/internal/ConfigurationService.java @@ -9,6 +9,7 @@ package org.opendaylight.controller.configuration.internal; +import java.io.File; import java.util.ArrayList; import java.util.Collections; import java.util.EnumSet; @@ -25,6 +26,7 @@ import org.opendaylight.controller.clustering.services.IClusterServices; 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; @@ -46,7 +48,7 @@ public class ConfigurationService implements IConfigurationService, ICacheUpdate 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 configEvent; private Set configurationAwareList = Collections @@ -105,21 +107,66 @@ public class ConfigurationService implements IConfigurationService, ICacheUpdate return saveConfigurationsInternal(); } + + private List getContainerDirectoryList() { + List containerList = new ArrayList(); + 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 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"); } } diff --git a/opendaylight/configuration/implementation/src/main/java/org/opendaylight/controller/configuration/internal/ContainerConfigurationService.java b/opendaylight/configuration/implementation/src/main/java/org/opendaylight/controller/configuration/internal/ContainerConfigurationService.java index 9c1d391daa..3e067254ed 100644 --- a/opendaylight/configuration/implementation/src/main/java/org/opendaylight/controller/configuration/internal/ContainerConfigurationService.java +++ b/opendaylight/configuration/implementation/src/main/java/org/opendaylight/controller/configuration/internal/ContainerConfigurationService.java @@ -9,7 +9,6 @@ package org.opendaylight.controller.configuration.internal; -import java.io.File; import java.util.ArrayList; import java.util.Collections; import java.util.Dictionary; @@ -52,14 +51,10 @@ public class ContainerConfigurationService implements IConfigurationContainerSer private static final Logger logger = LoggerFactory.getLogger(ContainerConfigurationService.class); private IClusterContainerServices clusterServices; private ConcurrentMap 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 configurationAwareList = Collections .synchronizedSet(new HashSet()); - private String root; private ObjectReader objReader; private ObjectWriter objWriter; @@ -93,14 +88,9 @@ public class ContainerConfigurationService implements IConfigurationContainerSer 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() { @@ -119,17 +109,18 @@ public class ContainerConfigurationService implements IConfigurationContainerSer * 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()); diff --git a/opendaylight/containermanager/implementation/src/main/java/org/opendaylight/controller/containermanager/internal/ContainerManager.java b/opendaylight/containermanager/implementation/src/main/java/org/opendaylight/controller/containermanager/internal/ContainerManager.java index ad897fd689..0fee183b67 100644 --- a/opendaylight/containermanager/implementation/src/main/java/org/opendaylight/controller/containermanager/internal/ContainerManager.java +++ b/opendaylight/containermanager/implementation/src/main/java/org/opendaylight/controller/containermanager/internal/ContainerManager.java @@ -9,7 +9,6 @@ package org.opendaylight.controller.containermanager.internal; -import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.ObjectInputStream; @@ -751,26 +750,6 @@ public class ContainerManager extends Authorization implements IContaine 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 @@ -1013,19 +992,6 @@ public class ContainerManager extends Authorization implements IContaine 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 ncList, UpdateType update, boolean notifyLocal) { diff --git a/opendaylight/distribution/opendaylight/pom.xml b/opendaylight/distribution/opendaylight/pom.xml index 28637bcf46..fca4936c7f 100644 --- a/opendaylight/distribution/opendaylight/pom.xml +++ b/opendaylight/distribution/opendaylight/pom.xml @@ -51,6 +51,16 @@ org.opendaylight.controller sal-broker-impl ${mdsal.version} + + + org.opendaylight.controller + sal-remote + ${mdsal.version} + + + org.opendaylight.controller + sal-restconf-broker + ${mdsal.version} org.opendaylight.controller @@ -175,6 +185,16 @@ concepts ${yangtools.version} + + org.opendaylight.yangtools + restconf-client-api + ${yangtools.version} + + + org.opendaylight.yangtools + restconf-client-impl + ${yangtools.version} + @@ -1248,6 +1268,10 @@ io.netty netty-common + + io.netty + netty-codec-http + diff --git a/opendaylight/forwardingrulesmanager/implementation/src/main/java/org/opendaylight/controller/forwardingrulesmanager/internal/ForwardingRulesManager.java b/opendaylight/forwardingrulesmanager/implementation/src/main/java/org/opendaylight/controller/forwardingrulesmanager/internal/ForwardingRulesManager.java index bce7dd30ba..b94103fb1c 100644 --- a/opendaylight/forwardingrulesmanager/implementation/src/main/java/org/opendaylight/controller/forwardingrulesmanager/internal/ForwardingRulesManager.java +++ b/opendaylight/forwardingrulesmanager/implementation/src/main/java/org/opendaylight/controller/forwardingrulesmanager/internal/ForwardingRulesManager.java @@ -331,7 +331,7 @@ public class ForwardingRulesManager implements for (FlowEntryInstall installEntry : toInstallSafe) { // Install and update database - Status ret = addEntriesInternal(installEntry, async); + Status ret = addEntryInternal(installEntry, async); if (ret.isSuccess()) { oneSucceded = true; @@ -494,7 +494,7 @@ public class ForwardingRulesManager implements } // Install new entries for (FlowEntryInstall newEntry : toInstallSafe) { - succeeded = this.addEntriesInternal(newEntry, async); + succeeded = this.addEntryInternal(newEntry, async); } } else { /* @@ -554,7 +554,9 @@ public class ForwardingRulesManager implements /** * This is the function that modifies the final container flows merged * entries on the network node and update the database. It expects that all - * the validity checks are passed + * the validity checks are passed. + * This function is supposed to be called only on the controller on which + * the IFRM call is executed. * * @param currentEntries * @param newEntries @@ -564,13 +566,13 @@ public class ForwardingRulesManager implements * contain the unique id assigned to this request */ private Status modifyEntryInternal(FlowEntryInstall currentEntries, FlowEntryInstall newEntries, boolean async) { + Status status = new Status(StatusCode.UNDEFINED); FlowEntryDistributionOrderFutureTask futureStatus = distributeWorkOrder(currentEntries, newEntries, UpdateType.CHANGED); if (futureStatus != null) { - Status retStatus = new Status(StatusCode.UNDEFINED); try { - retStatus = futureStatus.get(); - if (retStatus.getCode() + status = futureStatus.get(); + if (status.getCode() .equals(StatusCode.TIMEOUT)) { // A timeout happened, lets cleanup the workMonitor workMonitor.remove(futureStatus.getOrder()); @@ -580,30 +582,31 @@ public class ForwardingRulesManager implements } catch (ExecutionException e) { log.error("", e); } - return retStatus; } else { // Modify the flow on the network node - Status status = async ? programmer.modifyFlowAsync(currentEntries.getNode(), currentEntries.getInstall() - .getFlow(), newEntries.getInstall() - .getFlow()) : programmer.modifyFlow(currentEntries.getNode(), currentEntries.getInstall() - .getFlow(), newEntries.getInstall() - .getFlow()); + status = modifyEntryInHw(currentEntries, newEntries, async); + } - if (!status.isSuccess()) { - log.trace("SDN Plugin failed to program the flow: {}. The failure is: {}", newEntries.getInstall(), - status.getDescription()); - return status; - } + if (!status.isSuccess()) { + log.trace("{} SDN Plugin failed to program the flow: {}. The failure is: {}", + (futureStatus != null) ? "Remote" : "Local", newEntries.getInstall(), status.getDescription()); + return status; + } - log.trace("Modified {} => {}", currentEntries.getInstall(), newEntries.getInstall()); + log.trace("Modified {} => {}", currentEntries.getInstall(), newEntries.getInstall()); - // Update DB - newEntries.setRequestId(status.getRequestId()); - updateSwViews(currentEntries, false); - updateSwViews(newEntries, true); + // Update DB + newEntries.setRequestId(status.getRequestId()); + updateSwViews(currentEntries, false); + updateSwViews(newEntries, true); - return status; - } + return status; + } + + private Status modifyEntryInHw(FlowEntryInstall currentEntries, FlowEntryInstall newEntries, boolean async) { + return async ? programmer.modifyFlowAsync(currentEntries.getNode(), currentEntries.getInstall().getFlow(), + newEntries.getInstall().getFlow()) : programmer.modifyFlow(currentEntries.getNode(), currentEntries + .getInstall().getFlow(), newEntries.getInstall().getFlow()); } /** @@ -672,6 +675,8 @@ public class ForwardingRulesManager implements * This is the function that removes the final container flows merged entry * from the network node and update the database. It expects that all the * validity checks are passed + * This function is supposed to be called only on the controller on which + * the IFRM call is executed. * * @param entry * the flow entry to remove @@ -681,13 +686,12 @@ public class ForwardingRulesManager implements * contain the unique id assigned to this request */ private Status removeEntryInternal(FlowEntryInstall entry, boolean async) { + Status status = new Status(StatusCode.UNDEFINED); FlowEntryDistributionOrderFutureTask futureStatus = distributeWorkOrder(entry, null, UpdateType.REMOVED); if (futureStatus != null) { - Status retStatus = new Status(StatusCode.UNDEFINED); try { - retStatus = futureStatus.get(); - if (retStatus.getCode() - .equals(StatusCode.TIMEOUT)) { + status = futureStatus.get(); + if (status.getCode().equals(StatusCode.TIMEOUT)) { // A timeout happened, lets cleanup the workMonitor workMonitor.remove(futureStatus.getOrder()); } @@ -696,28 +700,31 @@ public class ForwardingRulesManager implements } catch (ExecutionException e) { log.error("", e); } - return retStatus; } else { // Mark the entry to be deleted (for CC just in case we fail) entry.toBeDeleted(); // Remove from node - Status status = async ? programmer.removeFlowAsync(entry.getNode(), entry.getInstall() - .getFlow()) : programmer.removeFlow(entry.getNode(), entry.getInstall() - .getFlow()); - - if (!status.isSuccess()) { - log.trace("SDN Plugin failed to remove the flow: {}. The failure is: {}", entry.getInstall(), - status.getDescription()); - return status; - } - log.trace("Removed {}", entry.getInstall()); - - // Update DB - updateSwViews(entry, false); + status = removeEntryInHw(entry, async); + } + if (!status.isSuccess()) { + log.trace("{} SDN Plugin failed to remove the flow: {}. The failure is: {}", + (futureStatus != null) ? "Remote" : "Local", entry.getInstall(), status.getDescription()); return status; } + + log.trace("Removed {}", entry.getInstall()); + + // Update DB + updateSwViews(entry, false); + + return status; + } + + private Status removeEntryInHw(FlowEntryInstall entry, boolean async) { + return async ? programmer.removeFlowAsync(entry.getNode(), entry.getInstall().getFlow()) : programmer + .removeFlow(entry.getNode(), entry.getInstall().getFlow()); } /** @@ -725,6 +732,8 @@ public class ForwardingRulesManager implements * on the network node and updates the database. It expects that all the * validity and conflict checks are passed. That means it does not check * whether this flow would conflict or overwrite an existing one. + * This function is supposed to be called only on the controller on which + * the IFRM call is executed. * * @param entry * the flow entry to install @@ -733,14 +742,13 @@ public class ForwardingRulesManager implements * @return the status of this request. In case of asynchronous call, it will * contain the unique id assigned to this request */ - private Status addEntriesInternal(FlowEntryInstall entry, boolean async) { + private Status addEntryInternal(FlowEntryInstall entry, boolean async) { + Status status = new Status(StatusCode.UNDEFINED); FlowEntryDistributionOrderFutureTask futureStatus = distributeWorkOrder(entry, null, UpdateType.ADDED); if (futureStatus != null) { - Status retStatus = new Status(StatusCode.UNDEFINED); try { - retStatus = futureStatus.get(); - if (retStatus.getCode() - .equals(StatusCode.TIMEOUT)) { + status = futureStatus.get(); + if (status.getCode().equals(StatusCode.TIMEOUT)) { // A timeout happened, lets cleanup the workMonitor workMonitor.remove(futureStatus.getOrder()); } @@ -749,27 +757,29 @@ public class ForwardingRulesManager implements } catch (ExecutionException e) { log.error("", e); } - return retStatus; } else { - // Install the flow on the network node - Status status = async ? programmer.addFlowAsync(entry.getNode(), entry.getInstall() - .getFlow()) : programmer.addFlow(entry.getNode(), entry.getInstall() - .getFlow()); + status = addEntryInHw(entry, async); + } - if (!status.isSuccess()) { - log.trace("SDN Plugin failed to program the flow: {}. The failure is: {}", entry.getInstall(), - status.getDescription()); - return status; - } + if (!status.isSuccess()) { + log.trace("{} SDN Plugin failed to program the flow: {}. The failure is: {}", + (futureStatus != null) ? "Remote" : "Local", entry.getInstall(), status.getDescription()); + return status; + } + + log.trace("Added {}", entry.getInstall()); - log.trace("Added {}", entry.getInstall()); + // Update DB + entry.setRequestId(status.getRequestId()); + updateSwViews(entry, true); - // Update DB - entry.setRequestId(status.getRequestId()); - updateSwViews(entry, true); + return status; + } - return status; - } + private Status addEntryInHw(FlowEntryInstall entry, boolean async) { + // Install the flow on the network node + return async ? programmer.addFlowAsync(entry.getNode(), entry.getInstall().getFlow()) : programmer.addFlow( + entry.getNode(), entry.getInstall().getFlow()); } /** @@ -2526,13 +2536,13 @@ public class ForwardingRulesManager implements FlowEntryInstall feiNew = workOrder.get(fe); switch (fe.getUpType()) { case ADDED: - gotStatus = addEntriesInternal(feiCurrent, false); + gotStatus = addEntryInHw(feiCurrent, false); break; case CHANGED: - gotStatus = modifyEntryInternal(feiCurrent, feiNew, false); + gotStatus = modifyEntryInHw(feiCurrent, feiNew, false); break; case REMOVED: - gotStatus = removeEntryInternal(feiCurrent, false); + gotStatus = removeEntryInHw(feiCurrent, false); break; } // Remove the Order diff --git a/opendaylight/hosttracker/api/src/main/java/org/opendaylight/controller/hosttracker/IPHostId.java b/opendaylight/hosttracker/api/src/main/java/org/opendaylight/controller/hosttracker/IPHostId.java index 9e2123c6cd..b8b54b45ba 100644 --- a/opendaylight/hosttracker/api/src/main/java/org/opendaylight/controller/hosttracker/IPHostId.java +++ b/opendaylight/hosttracker/api/src/main/java/org/opendaylight/controller/hosttracker/IPHostId.java @@ -61,4 +61,19 @@ public class IPHostId implements IHostId, Serializable { return new IPHostId(addr); } + /* + * (non-Javadoc) + * + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("IP=["); + if (this.ipAddress != null) { + builder.append(this.ipAddress.getHostAddress()); + } + builder.append("]"); + return (builder.toString()); + } } diff --git a/opendaylight/hosttracker/api/src/main/java/org/opendaylight/controller/hosttracker/IPMacHostId.java b/opendaylight/hosttracker/api/src/main/java/org/opendaylight/controller/hosttracker/IPMacHostId.java index 4ab84eb653..e10c5d1a78 100644 --- a/opendaylight/hosttracker/api/src/main/java/org/opendaylight/controller/hosttracker/IPMacHostId.java +++ b/opendaylight/hosttracker/api/src/main/java/org/opendaylight/controller/hosttracker/IPMacHostId.java @@ -80,4 +80,24 @@ public class IPMacHostId implements IHostId, Serializable { return new IPMacHostId(ip, mac); } + /* + * (non-Javadoc) + * + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("IP=["); + if (this.ipAddress != null) { + builder.append(this.ipAddress.getHostAddress()); + } + builder.append("]") + .append("MAC=["); + if (this.macAddr != null) { + builder.append(this.macAddr.toString()); + } + builder.append("]"); + return (builder.toString()); + } } diff --git a/opendaylight/hosttracker/implementation/src/main/java/org/opendaylight/controller/hosttracker/internal/HostTracker.java b/opendaylight/hosttracker/implementation/src/main/java/org/opendaylight/controller/hosttracker/internal/HostTracker.java index 9cae4348b1..734a392bc1 100644 --- a/opendaylight/hosttracker/implementation/src/main/java/org/opendaylight/controller/hosttracker/internal/HostTracker.java +++ b/opendaylight/hosttracker/implementation/src/main/java/org/opendaylight/controller/hosttracker/internal/HostTracker.java @@ -948,6 +948,10 @@ public class HostTracker implements IfIptoHost, IfHostListener, ISwitchManagerAw } } + /* + * This thread runs every 4 seconds + */ + class OutStandingARPHandler extends TimerTask { @Override public void run() { @@ -955,53 +959,55 @@ public class HostTracker implements IfIptoHost, IfHostListener, ISwitchManagerAw return; } ARPPending arphost; - /* This routine runs every 4 seconds */ - logger.trace("Number of Entries in ARP Pending/Failed Lists: ARPPendingList = {}, failedARPReqList = {}", - ARPPendingList.size(), failedARPReqList.size()); - for (Entry entry : ARPPendingList.entrySet()) { - arphost = entry.getValue(); - - if (hostsDB.containsKey(arphost.getHostId())) { - // this host is already learned, shouldn't be in - // ARPPendingList - // Remove it and continue - logger.warn("Learned Host {} found in ARPPendingList", decodeIPFromId(arphost.getHostId())); - ARPPendingList.remove(entry.getKey()); - continue; - } - if (arphost.getSent_count() < hostRetryCount) { - /* - * No reply has been received of first ARP Req, send the - * next one. Before sending the ARP, check if ARPHandler is - * available or not - */ - if (hostFinder == null) { - logger.warn("ARPHandler Services are not available for Outstanding ARPs"); + try { + for (Entry entry : ARPPendingList.entrySet()) { + arphost = entry.getValue(); + + if (hostsDB.containsKey(arphost.getHostId())) { + // this host is already learned, shouldn't be in + // ARPPendingList + // Remove it and continue + logger.warn("Learned Host {} found in ARPPendingList", decodeIPFromId(arphost.getHostId())); + ARPPendingList.remove(entry.getKey()); continue; } - for (IHostFinder hf : hostFinder) { - hf.find(decodeIPFromId(arphost.getHostId())); - } - arphost.sent_count++; - logger.debug("ARP Sent from ARPPending List, IP: {}", decodeIPFromId(arphost.getHostId())); - } else if (arphost.getSent_count() >= hostRetryCount) { - /* - * ARP requests have been sent without receiving a reply, - * remove this from the pending list - */ - ARPPendingList.remove(entry.getKey()); - logger.debug("ARP reply not received after multiple attempts, removing from Pending List IP: {}", - decodeIPFromId(arphost.getHostId())); - /* - * Add this host to a different list which will be processed - * on link up events - */ - logger.debug("Adding the host to FailedARPReqList IP: {}", decodeIPFromId(arphost.getHostId())); - failedARPReqList.put(entry.getKey(), arphost); + if (arphost.getSent_count() < hostRetryCount) { + /* + * No reply has been received of first ARP Req, send the + * next one. Before sending the ARP, check if ARPHandler + * is available or not + */ + if (hostFinder == null) { + logger.warn("ARPHandler Services are not available for Outstanding ARPs"); + continue; + } + for (IHostFinder hf : hostFinder) { + hf.find(decodeIPFromId(arphost.getHostId())); + } + arphost.sent_count++; + logger.debug("ARP Sent from ARPPending List, IP: {}", decodeIPFromId(arphost.getHostId())); + } else if (arphost.getSent_count() >= hostRetryCount) { + /* + * ARP requests have been sent without receiving a + * reply, remove this from the pending list + */ + ARPPendingList.remove(entry.getKey()); + logger.debug( + "ARP reply not received after multiple attempts, removing from Pending List IP: {}", + decodeIPFromId(arphost.getHostId())); + /* + * Add this host to a different list which will be + * processed on link up events + */ + logger.debug("Adding the host to FailedARPReqList IP: {}", decodeIPFromId(arphost.getHostId())); + failedARPReqList.put(entry.getKey(), arphost); - } else { - logger.error("Inavlid arp_sent count for entry: {}", entry); + } else { + logger.error("Inavlid arp_sent count for entry: {}", entry); + } } + } catch (IllegalStateException e) { + logger.debug("IllegalStateException Received by OutStandingARPHandler from: {}", e.getMessage()); } } } @@ -1009,10 +1015,10 @@ public class HostTracker implements IfIptoHost, IfHostListener, ISwitchManagerAw private class ARPRefreshHandler extends TimerTask { @Override public void run() { - if (stopping) { + if ((clusterContainerService != null) && !clusterContainerService.amICoordinator()) { return; } - if ((clusterContainerService != null) && !clusterContainerService.amICoordinator()) { + if (stopping) { return; } if (!hostRefresh) { @@ -1026,49 +1032,54 @@ public class HostTracker implements IfIptoHost, IfHostListener, ISwitchManagerAw logger.error("ARPRefreshHandler(): hostsDB is not allocated yet:"); return; } - for (Entry entry : hostsDB.entrySet()) { - HostNodeConnector host = entry.getValue(); - if (host.isStaticHost()) { - /* this host was learned via API3, don't age it out */ - continue; - } - - short arp_cntdown = host.getArpSendCountDown(); - arp_cntdown--; - if (arp_cntdown > hostRetryCount) { - host.setArpSendCountDown(arp_cntdown); - } else if (arp_cntdown <= 0) { - /* - * No ARP Reply received in last 2 minutes, remove this host - * and inform applications - */ - removeKnownHost(entry.getKey()); - notifyHostLearnedOrRemoved(host, false); - } else if (arp_cntdown <= hostRetryCount) { - /* - * Use the services of arphandler to check if host is still - * there - */ - if (logger.isTraceEnabled()) { - logger.trace( - "ARP Probing ({}) for {}({})", - new Object[] { arp_cntdown, host.getNetworkAddress().getHostAddress(), - HexEncode.bytesToHexString(host.getDataLayerAddressBytes()) }); + try { + for (Entry entry : hostsDB.entrySet()) { + HostNodeConnector host = entry.getValue(); + if (host.isStaticHost()) { + /* this host was learned via API3, don't age it out */ + continue; } - host.setArpSendCountDown(arp_cntdown); - if (hostFinder == null) { + + short arp_cntdown = host.getArpSendCountDown(); + arp_cntdown--; + if (arp_cntdown > hostRetryCount) { + host.setArpSendCountDown(arp_cntdown); + } else if (arp_cntdown <= 0) { /* - * If hostfinder is not available, then can't send the - * probe. However, continue the age out the hosts since - * we don't know if the host is indeed out there or not. + * No ARP Reply received in last 2 minutes, remove this + * host and inform applications */ - logger.trace("ARPHandler is not avaialable, can't send the probe"); - continue; - } - for (IHostFinder hf : hostFinder) { - hf.probe(host); + removeKnownHost(entry.getKey()); + notifyHostLearnedOrRemoved(host, false); + } else if (arp_cntdown <= hostRetryCount) { + /* + * Use the services of arphandler to check if host is + * still there + */ + if (logger.isTraceEnabled()) { + logger.trace( + "ARP Probing ({}) for {}({})", + new Object[] { arp_cntdown, host.getNetworkAddress().getHostAddress(), + HexEncode.bytesToHexString(host.getDataLayerAddressBytes()) }); + } + host.setArpSendCountDown(arp_cntdown); + if (hostFinder == null) { + /* + * If hostfinder is not available, then can't send + * the probe. However, continue the age out the + * hosts since we don't know if the host is indeed + * out there or not. + */ + logger.trace("ARPHandler is not avaialable, can't send the probe"); + continue; + } + for (IHostFinder hf : hostFinder) { + hf.probe(host); + } } } + } catch (IllegalStateException e) { + logger.debug("IllegalStateException Received by ARPRefreshHandler from: {}", e.getMessage()); } } } diff --git a/opendaylight/logging/bridge/pom.xml b/opendaylight/logging/bridge/pom.xml index 0fd26dbbe3..3ceb5b1812 100644 --- a/opendaylight/logging/bridge/pom.xml +++ b/opendaylight/logging/bridge/pom.xml @@ -1,55 +1,71 @@ - - 4.0.0 - - org.opendaylight.controller - commons.opendaylight - 1.4.2-SNAPSHOT - ../../commons/opendaylight - - - scm:git:ssh://git.opendaylight.org:29418/controller.git - scm:git:ssh://git.opendaylight.org:29418/controller.git - https://wiki.opendaylight.org/view/OpenDaylight_Controller:Main - HEAD - + + 4.0.0 + + org.opendaylight.controller + commons.opendaylight + 1.4.2-SNAPSHOT + ../../commons/opendaylight + + + scm:git:ssh://git.opendaylight.org:29418/controller.git + scm:git:ssh://git.opendaylight.org:29418/controller.git + https://wiki.opendaylight.org/view/OpenDaylight_Controller:Main + HEAD + - logging.bridge - 0.4.2-SNAPSHOT - bundle + logging.bridge + 0.4.2-SNAPSHOT + bundle - - - org.slf4j - slf4j-api - - - equinoxSDK381 - org.eclipse.osgi - - + + + org.slf4j + slf4j-api + + + equinoxSDK381 + org.eclipse.osgi + + + junit + junit + test + + + org.opendaylight.yangtools + mockito-configuration + test + + + ch.qos.logback + logback-classic + test + + - - - - org.apache.felix - maven-bundle-plugin - ${bundle.plugin.version} - true - - - - org.slf4j, - org.osgi.framework, - org.osgi.service.log - - - org.opendaylight.controller.logging.bridge.internal.Activator - - - ${project.basedir}/META-INF - - - - + + + + org.apache.felix + maven-bundle-plugin + ${bundle.plugin.version} + true + + + + org.slf4j, + org.osgi.framework, + org.osgi.service.log + + + org.opendaylight.controller.logging.bridge.internal.Activator + + + ${project.basedir}/META-INF + + + + diff --git a/opendaylight/logging/bridge/src/main/java/org/opendaylight/controller/logging/bridge/internal/LogListenerImpl.java b/opendaylight/logging/bridge/src/main/java/org/opendaylight/controller/logging/bridge/internal/LogListenerImpl.java index 03719d567f..2f45c6f91b 100644 --- a/opendaylight/logging/bridge/src/main/java/org/opendaylight/controller/logging/bridge/internal/LogListenerImpl.java +++ b/opendaylight/logging/bridge/src/main/java/org/opendaylight/controller/logging/bridge/internal/LogListenerImpl.java @@ -26,19 +26,19 @@ public class LogListenerImpl implements LogListener { if (this.logger != null) { switch (entry.getLevel()) { case LogService.LOG_DEBUG: - this.logger.debug("Bundle:{} Message:{} Exception:{}", entry.getBundle() + this.logger.debug("Bundle:{} Message:{}", entry.getBundle() .getSymbolicName(), entry.getMessage(), entry.getException()); break; case LogService.LOG_INFO: - this.logger.info("Bundle:{} Message:{} Exception:{}", entry.getBundle() + this.logger.info("Bundle:{} Message:{}", entry.getBundle() .getSymbolicName(), entry.getMessage(), entry.getException()); break; case LogService.LOG_WARNING: - this.logger.warn("Bundle:{} Message:{} Exception:{}", entry.getBundle() + this.logger.warn("Bundle:{} Message:{}", entry.getBundle() .getSymbolicName(), entry.getMessage(), entry.getException()); break; case LogService.LOG_ERROR: - this.logger.error("Bundle:{} Message:{} Exception:{}", entry.getBundle() + this.logger.error("Bundle:{} Message:{}", entry.getBundle() .getSymbolicName(), entry.getMessage(), entry.getException()); break; } diff --git a/opendaylight/logging/bridge/src/test/java/org/opendaylight/controller/logging/bridge/internal/LogListenerImplTest.java b/opendaylight/logging/bridge/src/test/java/org/opendaylight/controller/logging/bridge/internal/LogListenerImplTest.java new file mode 100644 index 0000000000..2490c39171 --- /dev/null +++ b/opendaylight/logging/bridge/src/test/java/org/opendaylight/controller/logging/bridge/internal/LogListenerImplTest.java @@ -0,0 +1,67 @@ +/* + * 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.logging.bridge.internal; + +import org.junit.Test; +import org.osgi.framework.Bundle; +import org.osgi.framework.ServiceReference; +import org.osgi.service.log.LogEntry; +import org.osgi.service.log.LogService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; + +public class LogListenerImplTest { + private static final Logger logger = LoggerFactory.getLogger(LogListenerImplTest.class); + + @Test + public void test() { + LogListenerImpl tested = new LogListenerImpl(logger); + tested.logged(getEntry("m1", null)); + tested.logged(getEntry("m2", new RuntimeException())); + } + + private LogEntry getEntry(final String message, final Exception e) { + return new LogEntry() { + @Override + public Bundle getBundle() { + Bundle mock = mock(Bundle.class); + doReturn(null).when(mock).getSymbolicName(); + return mock; + } + + @Override + public ServiceReference getServiceReference() { + return null; + } + + @Override + public int getLevel() { + return LogService.LOG_INFO; + } + + @Override + public String getMessage() { + return message; + } + + @Override + public Throwable getException() { + return e; + } + + @Override + public long getTime() { + return 0; + } + }; + } + +} diff --git a/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/ComponentActivator.xtend b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/ComponentActivator.xtend index a6fc4b0a23..a59c2c1636 100644 --- a/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/ComponentActivator.xtend +++ b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/ComponentActivator.xtend @@ -251,6 +251,7 @@ package class SalCompatibilityProvider implements BindingAwareProvider { topology.dataService = session.getSALService(DataProviderService) tpProvider.dataService = session.getSALService(DataProviderService) + inventory.start(); tpProvider.start(); diff --git a/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/FlowProgrammerAdapter.xtend b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/FlowProgrammerAdapter.xtend index fac12ee10d..8a0874ee31 100644 --- a/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/FlowProgrammerAdapter.xtend +++ b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/FlowProgrammerAdapter.xtend @@ -199,9 +199,11 @@ class FlowProgrammerAdapter implements IPluginInFlowProgrammerService, SalFlowLi } private def Future> 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); @@ -212,7 +214,9 @@ class FlowProgrammerAdapter implements IPluginInFlowProgrammerService, SalFlowLi private def Future> 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(); @@ -227,6 +231,10 @@ class FlowProgrammerAdapter implements IPluginInFlowProgrammerService, SalFlowLi } private def toFutureStatus(Future> future){ + if(future == null){ + return toStatus(true); + } + try { val result = future.get(); return toStatus(result); diff --git a/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/InventoryAndReadAdapter.xtend b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/InventoryAndReadAdapter.xtend index 60e43247c2..0c211fd0aa 100644 --- a/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/InventoryAndReadAdapter.xtend +++ b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/InventoryAndReadAdapter.xtend @@ -11,6 +11,9 @@ import java.util.ArrayList 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 @@ -76,17 +79,18 @@ import static extension org.opendaylight.controller.sal.compatibility.NodeMappin 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; @@ -111,21 +115,34 @@ class InventoryAndReadAdapter implements IPluginInReadService, @Property List inventoryPublisher = new CopyOnWriteArrayList(); - def setInventoryPublisher(IPluginOutInventoryService listener){ + private final InventoryNotificationProvider inventoryNotificationProvider = new InventoryNotificationProvider(); + + private final Map> nodeToNodeConnectorsMap = new ConcurrentHashMap>(); + + 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() { @@ -140,33 +157,33 @@ class InventoryAndReadAdapter implements IPluginInReadService, override readAllFlow(Node node, boolean cached) { val output = new ArrayList(); - 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() @@ -180,35 +197,35 @@ class InventoryAndReadAdapter implements IPluginInReadService, } override readAllNodeConnector(Node node, boolean cached) { - - val ret = new ArrayList(); - 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(); + 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()); @@ -216,23 +233,23 @@ class InventoryAndReadAdapter implements IPluginInReadService, } override readAllNodeTable(Node node, boolean cached) { - val ret = new ArrayList(); - - 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(); + + 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); @@ -241,39 +258,39 @@ class InventoryAndReadAdapter implements IPluginInReadService, 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; @@ -282,30 +299,30 @@ class InventoryAndReadAdapter implements IPluginInReadService, 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); @@ -314,25 +331,25 @@ class InventoryAndReadAdapter implements IPluginInReadService, } 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); @@ -341,19 +358,22 @@ class InventoryAndReadAdapter implements IPluginInReadService, } override onNodeConnectorRemoved(NodeConnectorRemoved update) { - // NOOP + // Never received } override onNodeRemoved(NodeRemoved notification) { val properties = Collections.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) == null ){ + if(!isKnownNodeConnector(update.nodeConnectorRef.value)){ updateType = UpdateType.ADDED; + recordNodeConnector(update.nodeConnectorRef.value); } var nodeConnector = update.nodeConnectorRef.toADNodeConnector @@ -369,16 +389,16 @@ class InventoryAndReadAdapter implements IPluginInReadService, 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() { @@ -461,50 +481,50 @@ class InventoryAndReadAdapter implements IPluginInReadService, 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 @@ -515,101 +535,148 @@ class InventoryAndReadAdapter implements IPluginInReadService, 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(); - 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(); - - 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(); - - 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(); + 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(); + + 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(); + + 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 properties){ + for( publisher : inventoryPublisher){ + publisher.updateNode(node, updateType, properties); + } + } + + private def publishNodeConnectorUpdate(org.opendaylight.controller.sal.core.NodeConnector nodeConnector, UpdateType updateType, Set properties){ + for( publisher : inventoryPublisher){ + publisher.updateNodeConnector(nodeConnector, updateType, properties); + } + } + + private def isKnownNodeConnector(InstanceIdentifier 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 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 properties){ - for( publisher : inventoryPublisher){ - publisher.updateNodeConnector(nodeConnector, updateType, properties); - } - } + if(nodeConnectors == null){ + return false; + } + return nodeConnectors.contains(nodeConnectorPath); + } + + + private def recordNodeConnector(InstanceIdentifier 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(); + nodeToNodeConnectorsMap.put(nodePath, nodeConnectors); + } + + nodeConnectors.add(nodeConnectorPath); + } finally { + nodeToNodeConnectorsLock.unlock(); + } + } + + private def removeNodeConnectors(InstanceIdentifier nodeIdentifier){ + val nodePath = nodeIdentifier.path.get(1); + + nodeToNodeConnectorsMap.remove(nodePath); + } } diff --git a/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/InventoryNotificationProvider.java b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/InventoryNotificationProvider.java new file mode 100644 index 0000000000..23a98ff39a --- /dev/null +++ b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/InventoryNotificationProvider.java @@ -0,0 +1,59 @@ +package org.opendaylight.controller.sal.compatibility; + +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; + +import java.util.List; + +public class InventoryNotificationProvider implements AutoCloseable{ + + private ListenerRegistration nodeConnectorDataChangeListenerRegistration; + + private NodeConnectorDataChangeListener nodeConnectorDataChangeListener; + + private DataProviderService dataProviderService; + + private List 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 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 inventoryPublisher) { + this.inventoryPublisher = inventoryPublisher; + } +} diff --git a/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/NodeConnectorDataChangeListener.java b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/NodeConnectorDataChangeListener.java new file mode 100644 index 0000000000..eebba74244 --- /dev/null +++ b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/NodeConnectorDataChangeListener.java @@ -0,0 +1,77 @@ +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 inventoryPublisher; + + public List getInventoryPublisher() { + return this.inventoryPublisher; + } + + public void setInventoryPublisher(final List inventoryPublisher) { + this.inventoryPublisher = inventoryPublisher; + } + + @Override + public void onDataChanged(DataChangeEvent, DataObject> change) { + final Map,DataObject> createdOperationalData = change.getCreatedOperationalData(); + final Map,DataObject> updatedOperationalData = change.getUpdatedOperationalData(); + + final Set,DataObject>> createdEntries = createdOperationalData.entrySet(); + final Set,DataObject>> updatedEntries = new HashSet<>(); + + updatedEntries.addAll(updatedOperationalData.entrySet()); + updatedEntries.removeAll(createdEntries); + + for(final Map.Entry,DataObject> entry : createdEntries){ + publishNodeConnectorUpdate(entry, UpdateType.ADDED); + } + + for(final Map.Entry,DataObject> entry : updatedEntries){ + publishNodeConnectorUpdate(entry, UpdateType.CHANGED); + } + } + + private void publishNodeConnectorUpdate(final Map.Entry,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 _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 properties) { + LOG.debug("Publishing NodeConnector " + updateType.toString() + " nodeConnector Id = " + nodeConnector.getNodeConnectorIdAsString()); + + List _inventoryPublisher = getInventoryPublisher(); + for (final IPluginOutInventoryService publisher : _inventoryPublisher) { + publisher.updateNodeConnector(nodeConnector, updateType, properties); + } + } +} diff --git a/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/adsal/FlowServiceAdapter.java b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/adsal/FlowServiceAdapter.java index 40de6e5507..84508ca03e 100644 --- a/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/adsal/FlowServiceAdapter.java +++ b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/adsal/FlowServiceAdapter.java @@ -14,9 +14,7 @@ import org.opendaylight.controller.sal.binding.api.NotificationProviderService; import org.opendaylight.controller.sal.common.util.Futures; import org.opendaylight.controller.sal.common.util.Rpcs; import org.opendaylight.controller.sal.compatibility.InventoryMapping; -import org.opendaylight.controller.sal.compatibility.NodeMapping; import org.opendaylight.controller.sal.compatibility.ToSalConversionsUtils; -import org.opendaylight.controller.sal.core.ConstructionException; import org.opendaylight.controller.sal.flowprogrammer.Flow; import org.opendaylight.controller.sal.flowprogrammer.IFlowProgrammerListener; import org.opendaylight.controller.sal.flowprogrammer.IFlowProgrammerService; diff --git a/opendaylight/md-sal/inventory-manager/src/main/java/org/opendaylight/controller/md/inventory/manager/FlowCapableInventoryProvider.xtend b/opendaylight/md-sal/inventory-manager/src/main/java/org/opendaylight/controller/md/inventory/manager/FlowCapableInventoryProvider.xtend index 1a66b3ba16..43f48a50e5 100644 --- a/opendaylight/md-sal/inventory-manager/src/main/java/org/opendaylight/controller/md/inventory/manager/FlowCapableInventoryProvider.xtend +++ b/opendaylight/md-sal/inventory-manager/src/main/java/org/opendaylight/controller/md/inventory/manager/FlowCapableInventoryProvider.xtend @@ -64,6 +64,8 @@ class FlowCapableInventoryProvider implements AutoCloseable { class NodeChangeCommiter implements OpendaylightInventoryListener { + static val LOG = LoggerFactory.getLogger(NodeChangeCommiter); + @Property val FlowCapableInventoryProvider manager; @@ -76,6 +78,9 @@ class NodeChangeCommiter implements OpendaylightInventoryListener { // Check path val it = manager.startChange() + + LOG.debug("removing node connector : " + ref.value.toString()); + removeOperationalData(ref.value as InstanceIdentifier); commit() } @@ -93,6 +98,8 @@ class NodeChangeCommiter implements OpendaylightInventoryListener { data.addAugmentation(FlowCapableNodeConnector, augment) } + LOG.debug("updating node connector : " + ref.value.toString()); + putOperationalData(ref.value as InstanceIdentifier, data.build()); commit() } @@ -101,6 +108,8 @@ class NodeChangeCommiter implements OpendaylightInventoryListener { val ref = node.nodeRef; val it = manager.startChange() + LOG.debug("removing node : " + ref.value.toString()); + removeOperationalData(ref.value as InstanceIdentifier); commit() } @@ -117,6 +126,8 @@ class NodeChangeCommiter implements OpendaylightInventoryListener { data.addAugmentation(FlowCapableNode, augment) } + LOG.debug("updating node : " + ref.value.toString()); + putOperationalData(ref.value as InstanceIdentifier, data.build()) commit() } diff --git a/opendaylight/md-sal/model/model-flow-base/pom.xml b/opendaylight/md-sal/model/model-flow-base/pom.xml index a7c74c573b..d7d678d89a 100644 --- a/opendaylight/md-sal/model/model-flow-base/pom.xml +++ b/opendaylight/md-sal/model/model-flow-base/pom.xml @@ -19,7 +19,6 @@ org.opendaylight.yangtools.model opendaylight-l2-types - 2013.08.27.3 ${project.groupId} diff --git a/opendaylight/md-sal/model/model-flow-base/src/main/yang/opendaylight-match-types.yang b/opendaylight/md-sal/model/model-flow-base/src/main/yang/opendaylight-match-types.yang index 321e054097..b02b0dc25c 100644 --- a/opendaylight/md-sal/model/model-flow-base/src/main/yang/opendaylight-match-types.yang +++ b/opendaylight/md-sal/model/model-flow-base/src/main/yang/opendaylight-match-types.yang @@ -8,7 +8,7 @@ module opendaylight-match-types { import opendaylight-inventory {prefix inv;revision-date "2013-08-19";} revision "2013-10-26" { - description "Initial revision of macth types"; + description "Initial revision of match types"; } grouping "mac-address-filter" { diff --git a/opendaylight/md-sal/model/model-flow-base/src/main/yang/opendaylight-table-types.yang b/opendaylight/md-sal/model/model-flow-base/src/main/yang/opendaylight-table-types.yang index 118db1af06..e74b548342 100644 --- a/opendaylight/md-sal/model/model-flow-base/src/main/yang/opendaylight-table-types.yang +++ b/opendaylight/md-sal/model/model-flow-base/src/main/yang/opendaylight-table-types.yang @@ -191,6 +191,7 @@ module opendaylight-table-types { grouping set-field-match { list set-field-match { + key "match-type"; leaf match-type { type identityref { base match-field; diff --git a/opendaylight/md-sal/model/model-flow-service/pom.xml b/opendaylight/md-sal/model/model-flow-service/pom.xml index 55837564c3..5604ea98cf 100644 --- a/opendaylight/md-sal/model/model-flow-service/pom.xml +++ b/opendaylight/md-sal/model/model-flow-service/pom.xml @@ -29,7 +29,6 @@ org.opendaylight.yangtools.model opendaylight-l2-types - 2013.08.27.3 bundle diff --git a/opendaylight/md-sal/model/model-flow-service/src/main/yang/sal-flow.yang b/opendaylight/md-sal/model/model-flow-service/src/main/yang/sal-flow.yang index 091bd43e19..b3e6e450af 100644 --- a/opendaylight/md-sal/model/model-flow-service/src/main/yang/sal-flow.yang +++ b/opendaylight/md-sal/model/model-flow-service/src/main/yang/sal-flow.yang @@ -4,7 +4,9 @@ module sal-flow { import yang-ext {prefix ext; revision-date "2013-07-09";} import opendaylight-inventory {prefix inv;revision-date "2013-08-19";} - import opendaylight-flow-types {prefix types;revision-date "2013-10-26";} + import opendaylight-flow-types {prefix types;revision-date "2013-10-26";} + import opendaylight-group-types {prefix group-type;revision-date 2013-10-18;} + import opendaylight-meter-types {prefix meter-type;revision-date "2013-09-18";} import flow-capable-transaction {prefix tr;} import flow-errors {prefix error;} @@ -122,6 +124,28 @@ module sal-flow { uses error:error-message; uses tr:transaction-aware; uses tr:transaction-metadata; + choice object-reference { + case flow-ref{ + leaf flow-ref { + type types:flow-ref; + } + } + case group-ref{ + leaf group-ref { + type group-type:group-ref; + } + } + case meter-ref{ + leaf meter-ref { + type meter-type:meter-ref; + } + } + } + leaf node { + ext:context-reference "inv:node-context"; + type inv:node-ref; + } + } notification node-experimenter-error-notification { diff --git a/opendaylight/md-sal/pom.xml b/opendaylight/md-sal/pom.xml index 2f594148c9..f900c0b18c 100644 --- a/opendaylight/md-sal/pom.xml +++ b/opendaylight/md-sal/pom.xml @@ -102,24 +102,14 @@ UTF-8 - http://nexus.opendaylight.org/content - - 1.7 - 1.7 2.4.0 - 2.3.2 + 2.5 - 1.7.2 - 14.0.1 - 5.0.0 - 4.8.1 1.9.5 2.4.3 - 2.5 - 0.5.3.201107060350 jacoco @@ -133,82 +123,6 @@ 0.7.1-SNAPSHOT - - - - opendaylight-mirror - opendaylight-mirror - ${nexusproxy}/groups/public/ - - false - - - true - never - - - - - opendaylight-snapshot - opendaylight-snapshot - ${nexusproxy}/repositories/opendaylight.snapshot/ - - true - - - false - - - - - - - - - opendaylight-mirror - opendaylight-mirror - ${nexusproxy}/groups/public/ - - false - - - true - never - - - - - opendaylight-snapshot - opendaylight-snapshot - ${nexusproxy}/repositories/opendaylight.snapshot/ - - true - - - false - - - - - - - - opendaylight-release - ${nexusproxy}/repositories/opendaylight.release/ - - - - opendaylight-snapshot - ${nexusproxy}/repositories/opendaylight.snapshot/ - - - - website - ${sitedeploy} - - - - @@ -217,48 +131,17 @@ 1.4.01 - - - org.opendaylight.yangtools - yang-binding - ${yangtools.version} - - - org.opendaylight.yangtools - yang-model-util - ${yangtools.version} - - - org.opendaylight.yangtools - yang-common - ${yangtools.version} - - - org.opendaylight.yangtools - yang-data-api - ${yangtools.version} - - - org.opendaylight.yangtools - yang-data-impl - ${yangtools.version} - - - org.opendaylight.yangtools - yang-model-api - ${yangtools.version} - - - org.opendaylight.yangtools - yang-data-util - ${yangtools.version} - ${project.groupId} sal-connector-api ${project.version} + + org.opendaylight.controller + sal-binding-api + ${project.version} + org.opendaylight.controller sal @@ -270,6 +153,16 @@ + + org.opendaylight.controller + sal-remote + ${project.version} + + + org.opendaylight.controller + sal-binding-util + ${project.version} + @@ -277,11 +170,6 @@ slf4j-api ${slf4j.version} - - com.google.guava - guava - ${guava.version} - org.eclipse.xtend org.eclipse.xtend.lib @@ -292,19 +180,6 @@ org.osgi.core ${osgi.core.version} - - - junit - junit - ${junit.version} - test - - - org.mockito - mockito-all - ${mockito.version} - test - org.opendaylight.yangtools binding-generator-impl @@ -315,16 +190,19 @@ yang-parser-impl ${yangtools.version} + + + + org.mockito + mockito-all + ${mockito.version} + test + - - org.apache.maven.plugins - maven-release-plugin - ${releaseplugin.version} - org.apache.felix maven-bundle-plugin diff --git a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/AbstractBindingAwareConsumer.java b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/AbstractBindingAwareConsumer.java index fc145c8b16..02bb6b35b9 100644 --- a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/AbstractBindingAwareConsumer.java +++ b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/AbstractBindingAwareConsumer.java @@ -7,10 +7,7 @@ */ package org.opendaylight.controller.sal.binding.api; -import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext; -import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; -import org.osgi.framework.ServiceReference; public abstract class AbstractBindingAwareConsumer extends AbstractBrokerAwareActivator implements BindingAwareConsumer { diff --git a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/AbstractBindingAwareProvider.java b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/AbstractBindingAwareProvider.java index 9d3bff4ef8..068b6c204f 100644 --- a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/AbstractBindingAwareProvider.java +++ b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/AbstractBindingAwareProvider.java @@ -13,12 +13,10 @@ import java.util.Collections; import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ConsumerContext; import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext; import org.opendaylight.yangtools.yang.binding.RpcService; -import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; -import org.osgi.framework.ServiceReference; public abstract class AbstractBindingAwareProvider extends AbstractBrokerAwareActivator implements BindingAwareProvider { - + @Override protected final void onBrokerAvailable(BindingAwareBroker broker, BundleContext context) { ProviderContext ctx = broker.registerProvider(this, context); @@ -57,13 +55,13 @@ public abstract class AbstractBindingAwareProvider extends AbstractBrokerAwareAc public Collection getImplementations() { return Collections.emptySet(); } - + /** * Initialization of consumer context. - * + * * {@link ProviderContext} is replacement of {@link ConsumerContext} * so this method is not needed in case of Provider. - * + * */ @Deprecated @Override diff --git a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/NotificationProviderService.java b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/NotificationProviderService.java index c28b03eb65..08029dc52f 100644 --- a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/NotificationProviderService.java +++ b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/NotificationProviderService.java @@ -12,7 +12,6 @@ import java.util.concurrent.ExecutorService; import org.opendaylight.controller.md.sal.common.api.notify.NotificationPublishService; import org.opendaylight.yangtools.concepts.ListenerRegistration; -import org.opendaylight.yangtools.concepts.Registration; import org.opendaylight.yangtools.yang.binding.Notification; public interface NotificationProviderService extends NotificationService, NotificationPublishService { @@ -20,7 +19,7 @@ public interface NotificationProviderService extends NotificationService, Notifi /** * Deprecated. Use {@link #publish(Notification)}. - * + * * @param notification */ @Deprecated @@ -28,7 +27,7 @@ public interface NotificationProviderService extends NotificationService, Notifi /** * Deprecated. Use {@link #publish(Notification,ExecutorService)}. - * + * * @param notification */ @Deprecated @@ -36,17 +35,17 @@ public interface NotificationProviderService extends NotificationService, Notifi /** * Publishes a notification. - * + * * @param Notification * notification to publish. - * + * */ @Override void publish(Notification notification); /** * Publishes a notification, listener calls are done in provided executor. - * + * */ @Override void publish(Notification notification, ExecutorService service); diff --git a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/NotificationService.java b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/NotificationService.java index 10b29f7218..24ca2a3de7 100644 --- a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/NotificationService.java +++ b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/NotificationService.java @@ -7,25 +7,23 @@ */ package org.opendaylight.controller.sal.binding.api; -import org.opendaylight.controller.md.sal.common.api.notify.NotificationSubscriptionService; -import org.opendaylight.yangtools.concepts.ListenerRegistration; import org.opendaylight.yangtools.concepts.Registration; import org.opendaylight.yangtools.yang.binding.Notification; public interface NotificationService extends BindingAwareService { /** - * + * * Deprecated: use {@link #addNotificationListener(Class, NotificationListener)} istead. - * + * * @param listener */ @Deprecated void addNotificationListener(Class notificationType, NotificationListener listener); /** - * + * * Deprecated: use {@link #addNotificationListener(org.opendaylight.yangtools.yang.binding.NotificationListener)} istead. - * + * * @param listener */ @Deprecated @@ -45,10 +43,10 @@ public interface NotificationService extends BindingAwareService { @Deprecated void removeNotificationListener(Class notificationType, NotificationListener listener); - + /** * Register a generic listener for specified notification type only. - * + * * @param notificationType * @param listener * @return Registration for listener. To unregister listener invoke {@link Registration#close()} method. @@ -61,7 +59,7 @@ public interface NotificationService extends BindingAwareService { * Register a listener which implements generated notification interfaces derived from * {@link org.opendaylight.yangtools.yang.binding.NotificationListener}. * Listener is registered for all notifications present in implemented interfaces. - * + * * @param listener * @return Registration for listener. To unregister listener invoke {@link Registration#close()} method. */ diff --git a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/RpcConsumerRegistry.java b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/RpcConsumerRegistry.java index 33b384a94c..69a2108065 100644 --- a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/RpcConsumerRegistry.java +++ b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/RpcConsumerRegistry.java @@ -19,8 +19,6 @@ public interface RpcConsumerRegistry extends BindingAwareService { * Returns a session specific instance (implementation) of requested * YANG module implentation / service provided by consumer. * - * @param service - * Broker service * @return Session specific implementation of service */ T getRpcService(Class module); diff --git a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/RpcProviderRegistry.java b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/RpcProviderRegistry.java index fcf8ed5c9e..c64e24c9c2 100644 --- a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/RpcProviderRegistry.java +++ b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/RpcProviderRegistry.java @@ -11,23 +11,22 @@ import org.opendaylight.controller.md.sal.common.api.routing.RouteChangePublishe import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RoutedRpcRegistration; import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RpcRegistration; import org.opendaylight.controller.sal.binding.api.rpc.RpcContextIdentifier; -import org.opendaylight.yangtools.concepts.ListenerRegistration; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.opendaylight.yangtools.yang.binding.RpcService; /** * Interface defining provider's access to the Rpc Registry which could be used * to register their implementations of service to the MD-SAL. - * + * * @author ttkacik - * + * */ public interface RpcProviderRegistry extends // RpcConsumerRegistry, // RouteChangePublisher> { /** * Registers an global RpcService implementation. - * + * * @param type * @param implementation * @return @@ -36,10 +35,10 @@ public interface RpcProviderRegistry extends // throws IllegalStateException; /** - * + * * Register an Routed RpcService where routing is determined on annotated * (in YANG model) context-reference and value of annotated leaf. - * + * * @param type * Type of RpcService, use generated interface class, not your * implementation clas @@ -47,7 +46,7 @@ public interface RpcProviderRegistry extends // * Implementation of RpcService * @return Registration object for routed Rpc which could be used to close * an - * + * * @throws IllegalStateException */ RoutedRpcRegistration addRoutedRpcImplementation(Class type, T implementation) diff --git a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/data/DataModificationTransaction.java b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/data/DataModificationTransaction.java index 9ce11c71e4..7190638323 100644 --- a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/data/DataModificationTransaction.java +++ b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/data/DataModificationTransaction.java @@ -11,9 +11,9 @@ import java.util.EventListener; import java.util.concurrent.Future; import org.opendaylight.controller.md.sal.common.api.TransactionStatus; +import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler; import org.opendaylight.controller.md.sal.common.api.data.DataModification; import org.opendaylight.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.common.RpcResult; @@ -22,28 +22,28 @@ public interface DataModificationTransaction extends DataModification * The {@link Consumer} could initiate a commit of candidate data - * + * *

* The successful commit changes the state of the system and may affect * several components. - * + * *

* The effects of successful commit of data are described in the * specifications and YANG models describing the {@link Provider} components * of controller. It is assumed that {@link Consumer} has an understanding * of this changes. - * - * + * + * * @see DataCommitHandler for further information how two-phase commit is * processed. * @param store @@ -53,12 +53,12 @@ public interface DataModificationTransaction extends DataModification> commit(); - - - + + + /** * Register a listener for transaction - * + * * @param listener * @return */ @@ -68,13 +68,13 @@ public interface DataModificationTransaction extends DataModification, DataObject> { - + /** * Registers a data reader for particular subtree of overal YANG data tree. - * - * Registered data reader is called if anyone tries to read data from + * + * Registered data reader is called if anyone tries to read data from * paths which are nested to provided path. - * + * * @param path Subpath which is handled by registered data reader - * @param reader Instance of reader which + * @param reader Instance of reader which * @return Registration object for reader. Invoking {@link Registration#close()} will unregister reader. */ Registration,DataObject>> registerDataReader(InstanceIdentifier path,DataReader,DataObject> reader); diff --git a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/data/DataRefresher.java b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/data/DataRefresher.java index f54e1315be..3334f2a037 100644 --- a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/data/DataRefresher.java +++ b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/data/DataRefresher.java @@ -8,19 +8,18 @@ package org.opendaylight.controller.sal.binding.api.data; import org.opendaylight.controller.sal.binding.api.BindingAwareProvider; -import org.opendaylight.controller.sal.binding.api.BindingAwareProvider.ProviderFunctionality; /** * Trigger for refreshing of the data exposed by the {@link Provider} - * - * - * + * + * + * */ public interface DataRefresher extends BindingAwareProvider.ProviderFunctionality { /** * Fired when some component explicitly requested the data refresh. - * + * * The provider which exposed the {@link DataRefresher} should republish its * provided data by editing the data in all affected data stores. */ diff --git a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/data/RuntimeDataProvider.java b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/data/RuntimeDataProvider.java index 652e14bfa5..85a2b82ee0 100644 --- a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/data/RuntimeDataProvider.java +++ b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/data/RuntimeDataProvider.java @@ -7,23 +7,19 @@ */ package org.opendaylight.controller.sal.binding.api.data; -import java.util.Set; - import org.opendaylight.controller.md.sal.common.api.data.DataReader; import org.opendaylight.controller.sal.binding.api.BindingAwareProvider.ProviderFunctionality; -import org.opendaylight.controller.sal.common.DataStoreIdentifier; import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.DataRoot; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; /** - * Utility interface which does type capture for BindingAware DataReader. - * - * @author + * Utility interface which does type capture for BindingAware DataReader. + * + * @author * */ public interface RuntimeDataProvider extends ProviderFunctionality,DataReader, DataObject> { - - + + } diff --git a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/mount/MountInstance.java b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/mount/MountInstance.java index 844b03a180..b4441601cb 100644 --- a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/mount/MountInstance.java +++ b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/mount/MountInstance.java @@ -12,7 +12,6 @@ import org.opendaylight.controller.sal.binding.api.RpcConsumerRegistry; import org.opendaylight.controller.sal.binding.api.data.DataBrokerService; import org.opendaylight.yangtools.concepts.Identifiable; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.opendaylight.yangtools.yang.binding.RpcService; public interface MountInstance // extends // diff --git a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/mount/MountProviderService.java b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/mount/MountProviderService.java index f7b584507a..6af9093fdd 100644 --- a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/mount/MountProviderService.java +++ b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/mount/MountProviderService.java @@ -9,21 +9,19 @@ package org.opendaylight.controller.sal.binding.api.mount; import java.util.EventListener; -import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry; import org.opendaylight.yangtools.concepts.ListenerRegistration; -import org.opendaylight.yangtools.concepts.Registration; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; /** * Provider MountProviderService, this version allows access to MD-SAL services * specific for this mountpoint and registration / provision of interfaces for * mount point. - * + * * @author ttkacik - * + * */ public interface MountProviderService extends MountService { - + @Override public MountProviderInstance getMountPoint(InstanceIdentifier path); diff --git a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/rpc/RpcRouter.java b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/rpc/RpcRouter.java index 31fed62d87..81fe39c62e 100644 --- a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/rpc/RpcRouter.java +++ b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/rpc/RpcRouter.java @@ -14,17 +14,16 @@ import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RoutedRpcR import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RpcRegistration; import org.opendaylight.yangtools.yang.binding.BaseIdentity; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.opendaylight.yangtools.yang.binding.RpcImplementation; import org.opendaylight.yangtools.yang.binding.RpcService; /** * RpcRouter is responsible for selecting RpcService based on provided routing * context identifier {@link RpcRoutingTable#getContextIdentifier()} and path in * overal data tree (@link {@link InstanceIdentifier}. - * - * + * + * * @author Tony Tkacik - * + * * @param * Type of RpcService for which router provides routing information * and route selection. @@ -34,23 +33,23 @@ public interface RpcRouter extends // /** * Returns a type of RpcService which is served by this instance of router. - * + * * @return type of RpcService which is served by this instance of router. */ Class getServiceType(); - - + + /** * Returns a instance of T which is associated with this router instance * and routes messages based on routing tables. - * + * * @return type of RpcService which is served by this instance of router. */ T getInvocationProxy(); /** * Returns a routing table for particular route context - * + * * @param routeContext * @return Routing Table for particular route context. */ @@ -59,7 +58,7 @@ public interface RpcRouter extends // /** * Returns an instance of RpcService which is responsible for processing * particular path. - * + * * @param context * Rpc Routing Context * @param path @@ -72,15 +71,15 @@ public interface RpcRouter extends // /** * Returns a default fallback instance of RpcService which is responsible * for handling all unknown imports. - * + * * @return default instance responsible for processing RPCs. */ T getDefaultService(); Set> getContexts(); - + RoutedRpcRegistration addRoutedRpcImplementation(T service); - + RpcRegistration registerDefaultService(T service); } diff --git a/opendaylight/md-sal/sal-binding-broker/pom.xml b/opendaylight/md-sal/sal-binding-broker/pom.xml index e5a74e42a1..fd2c8a2fa4 100644 --- a/opendaylight/md-sal/sal-binding-broker/pom.xml +++ b/opendaylight/md-sal/sal-binding-broker/pom.xml @@ -101,7 +101,7 @@ org.opendaylight.controller.sal.binding.impl.*, org.opendaylight.controller.sal.binding.codegen, org.opendaylight.controller.sal.binding.codegen.*, - org.opendaylight.controller.sal.binding.dom.*, + org.opendaylight.controller.sal.binding.osgi.*, diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/BindingBrokerImplModule.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/BindingBrokerImplModule.java index ffc8379228..44a508c0a0 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/BindingBrokerImplModule.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/BindingBrokerImplModule.java @@ -23,8 +23,6 @@ import org.opendaylight.controller.sal.binding.impl.forward.DomForwardedBindingB import org.opendaylight.controller.sal.binding.impl.forward.DomForwardingUtils; import org.osgi.framework.BundleContext; -import com.google.common.util.concurrent.MoreExecutors; - /** * */ diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/DataBrokerImplModule.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/DataBrokerImplModule.java index 286b0c378c..7357926b9e 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/DataBrokerImplModule.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/DataBrokerImplModule.java @@ -7,17 +7,17 @@ */ package org.opendaylight.controller.config.yang.md.sal.binding.impl; -import java.util.concurrent.ExecutorService; - -import org.opendaylight.controller.sal.binding.codegen.impl.SingletonHolder; -import org.opendaylight.controller.sal.binding.impl.RootDataBrokerImpl; -import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingDomConnectorDeployer; -import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentConnector; -import org.opendaylight.controller.sal.binding.impl.forward.DomForwardedDataBrokerImpl; -import org.opendaylight.controller.sal.core.api.Broker.ProviderSession; -import org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMappingService; -import org.osgi.framework.BundleContext; -import org.osgi.framework.ServiceReference; +import java.util.concurrent.ExecutorService; + +import org.opendaylight.controller.sal.binding.codegen.impl.SingletonHolder; +import org.opendaylight.controller.sal.binding.impl.RootDataBrokerImpl; +import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingDomConnectorDeployer; +import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentConnector; +import org.opendaylight.controller.sal.binding.impl.forward.DomForwardedDataBrokerImpl; +import org.opendaylight.controller.sal.core.api.Broker.ProviderSession; +import org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMappingService; +import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceReference; /** * @@ -57,14 +57,14 @@ public final class DataBrokerImplModule extends dataBindingBroker = createStandAloneBroker(listeningExecutor); } dataBindingBroker.registerRuntimeBean(getRootRuntimeBeanRegistratorWrapper()); - + dataBindingBroker.setNotificationExecutor(SingletonHolder.getDefaultChangeEventExecutor()); return dataBindingBroker; } private BindingIndependentMappingService resolveMappingServiceDependency() { if(getMappingService() != null) { return getMappingServiceDependency(); } - + ServiceReference potentialMappingService = bundleContext.getServiceReference(BindingIndependentMappingService.class); if(potentialMappingService != null) { return bundleContext.getService(potentialMappingService); diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/NotificationBrokerImplModule.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/NotificationBrokerImplModule.java index 0a503d5642..b6c27a6332 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/NotificationBrokerImplModule.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/NotificationBrokerImplModule.java @@ -7,15 +7,10 @@ */ package org.opendaylight.controller.config.yang.md.sal.binding.impl; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; - import org.opendaylight.controller.sal.binding.codegen.impl.SingletonHolder; import org.opendaylight.controller.sal.binding.impl.NotificationBrokerImpl; import com.google.common.util.concurrent.ListeningExecutorService; -import com.google.common.util.concurrent.MoreExecutors; /** * diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/RuntimeMappingModule.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/RuntimeMappingModule.java index a2b3d17b7c..14006a3fce 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/RuntimeMappingModule.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/RuntimeMappingModule.java @@ -7,12 +7,11 @@ */ package org.opendaylight.controller.config.yang.md.sal.binding.impl; +import com.google.common.base.Optional; +import com.google.common.base.Preconditions; import java.util.Hashtable; import java.util.Map.Entry; import java.util.Set; - -import javassist.ClassPool; - import org.opendaylight.controller.sal.binding.codegen.impl.SingletonHolder; import org.opendaylight.yangtools.concepts.Delegator; import org.opendaylight.yangtools.sal.binding.generator.impl.RuntimeGeneratedMappingServiceImpl; @@ -29,8 +28,6 @@ import org.opendaylight.yangtools.yang.model.api.SchemaServiceListener; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceReference; -import com.google.common.base.Preconditions; - /** * */ @@ -147,6 +144,11 @@ public final class RuntimeMappingModule extends return delegate.getRpcQNamesFor(service); } + @Override + public Optional> getRpcServiceClassFor(String namespace, String revision) { + return delegate.getRpcServiceClassFor(namespace,revision); + } + public DataContainer dataObjectFromDataDom(Class inputClass, CompositeNode domInput) { return delegate.dataObjectFromDataDom(inputClass, domInput); } diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RpcRouterCodegenInstance.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RpcRouterCodegenInstance.java index 4f994e5673..5578f75ae2 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RpcRouterCodegenInstance.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RpcRouterCodegenInstance.java @@ -7,29 +7,26 @@ */ package org.opendaylight.controller.sal.binding.codegen.impl; -import org.opendaylight.yangtools.yang.binding.RpcService; -import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RoutedRpcRegistration; -import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RpcRegistration; -import org.opendaylight.controller.sal.binding.api.rpc.RpcRouter; -import org.opendaylight.controller.sal.binding.api.rpc.RpcRoutingTable; -import org.opendaylight.controller.sal.binding.codegen.RuntimeCodeHelper; -import org.opendaylight.yangtools.yang.binding.BaseIdentity; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; - -import static org.opendaylight.controller.sal.binding.codegen.RuntimeCodeHelper.*; +import static org.opendaylight.controller.sal.binding.codegen.RuntimeCodeHelper.setRoutingTable; +import java.util.HashMap; import java.util.Map; import java.util.Set; -import java.util.HashMap; -import org.opendaylight.yangtools.yang.binding.DataContainer; -import org.opendaylight.yangtools.yang.binding.RpcImplementation; -import org.opendaylight.controller.md.sal.common.api.routing.MutableRoutingTable; import org.opendaylight.controller.md.sal.common.api.routing.RouteChange; import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener; +import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RoutedRpcRegistration; +import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RpcRegistration; +import org.opendaylight.controller.sal.binding.api.rpc.RpcRouter; +import org.opendaylight.controller.sal.binding.api.rpc.RpcRoutingTable; +import org.opendaylight.controller.sal.binding.codegen.RuntimeCodeHelper; import org.opendaylight.yangtools.concepts.AbstractObjectRegistration; import org.opendaylight.yangtools.concepts.ListenerRegistration; import org.opendaylight.yangtools.concepts.util.ListenerRegistry; +import org.opendaylight.yangtools.yang.binding.BaseIdentity; +import org.opendaylight.yangtools.yang.binding.DataContainer; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.binding.RpcService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -66,11 +63,11 @@ public class RpcRouterCodegenInstance implements // Map, RpcRoutingTableImpl> mutableRoutingTables = new HashMap<>(); for (Class ctx : contexts) { RpcRoutingTableImpl table = new RpcRoutingTableImpl<>(name,ctx,type); - + @SuppressWarnings("rawtypes") Map invokerView = table.getRoutes(); - - setRoutingTable((RpcService) invocationProxy, ctx, invokerView); + + setRoutingTable(invocationProxy, ctx, invokerView); mutableRoutingTables.put(ctx, table); table.registerRouteChangeListener(this); } diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RpcRoutingTableImpl.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RpcRoutingTableImpl.java index 500b1b399e..ce159b8f3e 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RpcRoutingTableImpl.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RpcRoutingTableImpl.java @@ -7,24 +7,21 @@ */ package org.opendaylight.controller.sal.binding.codegen.impl; -import org.opendaylight.controller.sal.binding.api.rpc.RpcRoutingTable; -import org.opendaylight.yangtools.yang.binding.BaseIdentity; -import org.opendaylight.yangtools.yang.binding.RpcService; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; - import java.util.Collections; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.controller.md.sal.common.api.routing.RouteChangePublisher; import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener; +import org.opendaylight.controller.md.sal.common.api.routing.RouteChangePublisher; import org.opendaylight.controller.md.sal.common.impl.routing.RoutingUtils; +import org.opendaylight.controller.sal.binding.api.rpc.RpcRoutingTable; import org.opendaylight.yangtools.concepts.AbstractObjectRegistration; -import org.opendaylight.yangtools.concepts.Identifiable; import org.opendaylight.yangtools.concepts.ListenerRegistration; import org.opendaylight.yangtools.concepts.Mutable; +import org.opendaylight.yangtools.yang.binding.BaseIdentity; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.binding.RpcService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -44,7 +41,7 @@ implements // private RouteChangeListener, InstanceIdentifier> listener; private S defaultRoute; - + public RpcRoutingTableImpl(String routerName,Class contextType, Class serviceType) { super(); this.routerName = routerName; @@ -67,9 +64,9 @@ implements // @Override public , InstanceIdentifier>> ListenerRegistration registerRouteChangeListener( L listener) { - return (ListenerRegistration) new SingletonListenerRegistration(listener); + return new SingletonListenerRegistration(listener); } - + @Override public Class getIdentifier() { return contextType; @@ -79,7 +76,7 @@ implements // @SuppressWarnings("unchecked") public void updateRoute(InstanceIdentifier path, S service) { S previous = this.routes.put(path, service); - + LOGGER.debug("Route {} updated to {} in routing table {}",path,service,this); @SuppressWarnings("rawtypes") RouteChangeListener listenerCapture = listener; @@ -88,7 +85,7 @@ implements // } } - + @Override @SuppressWarnings("unchecked") public void removeRoute(InstanceIdentifier path) { @@ -100,7 +97,7 @@ implements // listenerCapture.onRouteChange(RoutingUtils.removalChange(contextType, path)); } } - + public void removeRoute(InstanceIdentifier path, S service) { @SuppressWarnings("rawtypes") RouteChangeListener listenerCapture = listener; @@ -123,12 +120,12 @@ implements // public Map, S> getRoutes() { return unmodifiableRoutes; } - + protected void removeAllReferences(S service) { - + } - - + + @Override public String toString() { diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/SingletonHolder.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/SingletonHolder.java index 244e350343..a0bbb28d9e 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/SingletonHolder.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/SingletonHolder.java @@ -9,9 +9,10 @@ package org.opendaylight.controller.sal.binding.codegen.impl; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ThreadFactory; +import javassist.ClassPool; + import org.opendaylight.controller.sal.binding.codegen.RuntimeCodeGenerator; import org.opendaylight.controller.sal.binding.spi.NotificationInvokerFactory; @@ -19,8 +20,6 @@ import com.google.common.util.concurrent.ListeningExecutorService; import com.google.common.util.concurrent.MoreExecutors; import com.google.common.util.concurrent.ThreadFactoryBuilder; -import javassist.ClassPool; - public class SingletonHolder { public static final ClassPool CLASS_POOL = new ClassPool(); @@ -30,6 +29,7 @@ public class SingletonHolder { public static final NotificationInvokerFactory INVOKER_FACTORY = RPC_GENERATOR_IMPL.getInvokerFactory(); private static ListeningExecutorService NOTIFICATION_EXECUTOR = null; private static ListeningExecutorService COMMIT_EXECUTOR = null; + private static ListeningExecutorService CHANGE_EVENT_EXECUTOR = null; public static synchronized final ListeningExecutorService getDefaultNotificationExecutor() { if (NOTIFICATION_EXECUTOR == null) { @@ -65,4 +65,21 @@ public class SingletonHolder { 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(); + /* + * 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); + CHANGE_EVENT_EXECUTOR = MoreExecutors.listeningDecorator(executor); + } + + return CHANGE_EVENT_EXECUTOR; + } } diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/DataBrokerImpl.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/DataBrokerImpl.java index 3cc66c30c1..16d5a24cb5 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/DataBrokerImpl.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/DataBrokerImpl.java @@ -7,28 +7,62 @@ */ package org.opendaylight.controller.sal.binding.impl; -import java.util.Set; -import java.util.concurrent.Future; -import java.util.concurrent.atomic.AtomicLong; - -import org.opendaylight.controller.md.sal.common.impl.service.AbstractDataBroker; -import org.opendaylight.controller.sal.binding.api.data.DataChangeListener; -import org.opendaylight.controller.sal.binding.api.data.DataProviderService; -import org.opendaylight.controller.sal.binding.impl.util.BindingAwareDataReaderRouter; -import org.opendaylight.controller.sal.common.DataStoreIdentifier; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.DataRoot; -import org.opendaylight.yangtools.yang.binding.Identifiable; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.opendaylight.yangtools.yang.common.RpcResult; +import java.util.Map; +import java.util.Map.Entry; +import java.util.concurrent.Future; +import java.util.concurrent.atomic.AtomicLong; + +import org.opendaylight.controller.md.sal.common.impl.service.AbstractDataBroker; +import org.opendaylight.controller.sal.binding.api.data.DataChangeListener; +import org.opendaylight.controller.sal.binding.api.data.DataProviderService; +import org.opendaylight.controller.sal.binding.impl.util.BindingAwareDataReaderRouter; +import org.opendaylight.controller.sal.common.DataStoreIdentifier; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.DataRoot; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.binding.util.DataObjectReadingUtil; +import org.opendaylight.yangtools.yang.common.RpcResult; + +import com.google.common.base.Predicate; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableMap.Builder; +import com.google.common.collect.Maps; public class DataBrokerImpl extends AbstractDataBroker, DataObject, DataChangeListener> // implements DataProviderService, AutoCloseable { + private final static class ContainsWildcarded implements Predicate> { + + private final InstanceIdentifier key; + + public ContainsWildcarded(InstanceIdentifier key) { + this.key = key; + } + + @Override + public boolean apply(InstanceIdentifier input) { + return key.containsWildcarded(input); + } + } + + private final static class IsContainedWildcarded implements Predicate> { + + private final InstanceIdentifier key; + + public IsContainedWildcarded(InstanceIdentifier key) { + this.key = key; + } + + @Override + public boolean apply(InstanceIdentifier input) { + return input.containsWildcarded(key); + } + } + private final AtomicLong nextTransaction = new AtomicLong(); private final AtomicLong createdTransactionsCount = new AtomicLong(); - + public AtomicLong getCreatedTransactionsCount() { return createdTransactionsCount; } @@ -104,24 +138,40 @@ public class DataBrokerImpl extends AbstractDataBroker key, - Set> paths) { - if (paths.contains(key)) { - return true; - } - for (InstanceIdentifier path : paths) { - if (key.containsWildcarded(path)) { - return true; + protected Predicate> createContainsPredicate(final + InstanceIdentifier key) { + return new ContainsWildcarded(key); + } + + @Override + protected Predicate> createIsContainedPredicate(final + InstanceIdentifier key) { + return new IsContainedWildcarded(key); + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + @Override + protected Map, DataObject> deepGetBySubpath( + Map, DataObject> dataSet, + InstanceIdentifier path) { + Builder, DataObject> builder = ImmutableMap.builder(); + Map, DataObject> potential = Maps.filterKeys(dataSet, createIsContainedPredicate(path)); + for(Entry, DataObject> entry : potential.entrySet()) { + try { + builder.putAll(DataObjectReadingUtil.readData(entry.getValue(),(InstanceIdentifier)entry.getKey(),path)); + } catch (Exception e) { + // FIXME : Log exception; } } - return false; - } + return builder.build(); + + } + } diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/DataTransactionImpl.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/DataTransactionImpl.java index 290ff2232f..1ea2eba87f 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/DataTransactionImpl.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/DataTransactionImpl.java @@ -10,18 +10,17 @@ package org.opendaylight.controller.sal.binding.impl; import org.opendaylight.controller.md.sal.common.api.TransactionStatus; import org.opendaylight.controller.md.sal.common.impl.service.AbstractDataTransaction; import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction; -import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction.DataTransactionListener; import org.opendaylight.yangtools.concepts.ListenerRegistration; import org.opendaylight.yangtools.concepts.util.ListenerRegistry; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -public class DataTransactionImpl extends AbstractDataTransaction, DataObject> +public class DataTransactionImpl extends AbstractDataTransaction, DataObject> implements DataModificationTransaction { private final ListenerRegistry listeners = new ListenerRegistry(); - - - + + + public DataTransactionImpl(Object identifier,DataBrokerImpl dataBroker) { super(identifier,dataBroker); } @@ -31,6 +30,7 @@ public class DataTransactionImpl extends AbstractDataTransaction listenerRegistration : listeners) { listenerRegistration.getInstance().onStatusUpdated(this, status); diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/NotificationBrokerImpl.xtend b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/NotificationBrokerImpl.xtend index d997af5912..9a431fec74 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/NotificationBrokerImpl.xtend +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/NotificationBrokerImpl.xtend @@ -23,7 +23,10 @@ import org.opendaylight.yangtools.yang.binding.Notification import org.slf4j.LoggerFactory import org.opendaylight.controller.sal.binding.codegen.impl.SingletonHolder import com.google.common.collect.Multimaps import org.opendaylight.yangtools.concepts.util.ListenerRegistry -import org.opendaylight.controller.sal.binding.api.NotificationProviderService.NotificationInterestListener +import org.opendaylight.controller.sal.binding.api.NotificationProviderService.NotificationInterestListener import java.util.Set +import java.util.Set +import com.google.common.collect.ImmutableSet +import java.util.concurrent.Future class NotificationBrokerImpl implements NotificationProviderService, AutoCloseable { @@ -100,9 +103,17 @@ class NotificationBrokerImpl implements NotificationProviderService, AutoCloseab listenerToNotify = listenerToNotify + listeners.get(type as Class) } val tasks = listenerToNotify.map[new NotifyTask(it, notification)].toSet; - executor.invokeAll(tasks); + submitAll(executor,tasks); } - + + def submitAll(ExecutorService service, Set tasks) { + val ret = ImmutableSet.>builder(); + for(task : tasks) { + ret.add(service.submit(task)); + } + return ret.build(); + } + override registerNotificationListener(Class notificationType, NotificationListener listener) { val reg = new GenericNotificationRegistration(notificationType, listener, this); diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/RootBindingAwareBroker.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/RootBindingAwareBroker.java index 5292487d03..3ad1dabffe 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/RootBindingAwareBroker.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/RootBindingAwareBroker.java @@ -7,8 +7,7 @@ */ package org.opendaylight.controller.sal.binding.impl; -import static com.google.common.base.Preconditions.checkState; - +import com.google.common.collect.ImmutableClassToInstanceMap; import org.opendaylight.controller.md.sal.binding.util.AbstractBindingSalProviderInstance; import org.opendaylight.controller.md.sal.binding.util.BindingContextUtils; import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener; @@ -33,8 +32,7 @@ import org.opendaylight.yangtools.yang.binding.RpcService; import org.osgi.framework.BundleContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - -import com.google.common.collect.ImmutableClassToInstanceMap; +import static com.google.common.base.Preconditions.checkState; public class RootBindingAwareBroker implements // Mutable, // diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/RpcProviderRegistryImpl.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/RpcProviderRegistryImpl.java index f934571101..e98d5b9942 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/RpcProviderRegistryImpl.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/RpcProviderRegistryImpl.java @@ -7,29 +7,28 @@ */ package org.opendaylight.controller.sal.binding.impl; +import static com.google.common.base.Preconditions.checkState; + import java.util.EventListener; +import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; -import java.util.HashMap; import java.util.Set; import java.util.WeakHashMap; -import javax.swing.tree.ExpandVetoException; - import org.opendaylight.controller.md.sal.common.api.routing.RouteChange; import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener; import org.opendaylight.controller.md.sal.common.api.routing.RouteChangePublisher; import org.opendaylight.controller.md.sal.common.impl.routing.RoutingUtils; -import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry; import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RoutedRpcRegistration; import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RpcRegistration; +import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry; +import org.opendaylight.controller.sal.binding.api.rpc.RpcContextIdentifier; import org.opendaylight.controller.sal.binding.api.rpc.RpcRouter; import org.opendaylight.controller.sal.binding.codegen.RuntimeCodeGenerator; import org.opendaylight.controller.sal.binding.codegen.RuntimeCodeHelper; import org.opendaylight.controller.sal.binding.codegen.impl.SingletonHolder; -import org.opendaylight.controller.sal.binding.api.rpc.RpcContextIdentifier; import org.opendaylight.yangtools.concepts.AbstractObjectRegistration; -import org.opendaylight.yangtools.concepts.Identifiable; import org.opendaylight.yangtools.concepts.ListenerRegistration; import org.opendaylight.yangtools.concepts.util.ListenerRegistry; import org.opendaylight.yangtools.yang.binding.BaseIdentity; @@ -38,8 +37,6 @@ import org.opendaylight.yangtools.yang.binding.RpcService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import static com.google.common.base.Preconditions.*; - public class RpcProviderRegistryImpl implements // RpcProviderRegistry, // RouteChangePublisher> { @@ -56,7 +53,7 @@ public class RpcProviderRegistryImpl implements // private final String name; - private ListenerRegistry globalRpcListeners = ListenerRegistry.create(); + private final ListenerRegistry globalRpcListeners = ListenerRegistry.create(); public String getName() { return name; @@ -96,7 +93,6 @@ public class RpcProviderRegistryImpl implements // @Override public final T getRpcService(Class type) { - @SuppressWarnings("unchecked") T potentialProxy = (T) publicProxies.get(type); if (potentialProxy != null) { return potentialProxy; @@ -109,7 +105,7 @@ public class RpcProviderRegistryImpl implements // potentialProxy = (T) publicProxies.get(type); if (potentialProxy != null) { - return (T) potentialProxy; + return potentialProxy; } T proxy = rpcFactory.getDirectProxyFor(type); LOG.debug("Created {} as public proxy for {} in {}", proxy, type.getSimpleName(), this); @@ -151,10 +147,10 @@ public class RpcProviderRegistryImpl implements // LOG.error("Unhandled exception during invoking listener {}", e); } } - + } - private void notifyListenersRoutedCreated(RpcRouter router) { + private void notifyListenersRoutedCreated(RpcRouter router) { for (ListenerRegistration listener : routerInstantiationListener) { try { @@ -196,7 +192,7 @@ public class RpcProviderRegistryImpl implements // public interface RouterInstantiationListener extends EventListener { void onRpcRouterCreated(RpcRouter router); } - + public ListenerRegistration registerGlobalRpcRegistrationListener(GlobalRpcRegistrationListener listener) { return globalRpcListeners.register(listener); } @@ -204,7 +200,7 @@ public class RpcProviderRegistryImpl implements // public interface GlobalRpcRegistrationListener extends EventListener { void onGlobalRpcRegistered(Class cls); void onGlobalRpcUnregistered(Class cls); - + } private class RouteChangeForwarder implements diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingIndependentConnector.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingIndependentConnector.java index 5630664a67..e48ebbc057 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingIndependentConnector.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingIndependentConnector.java @@ -45,8 +45,6 @@ import org.opendaylight.controller.sal.binding.api.data.DataProviderService; import org.opendaylight.controller.sal.binding.api.data.RuntimeDataProvider; import org.opendaylight.controller.sal.binding.api.rpc.RpcContextIdentifier; import org.opendaylight.controller.sal.binding.api.rpc.RpcRouter; -import org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMappingService; -import org.opendaylight.yangtools.yang.data.impl.codec.DeserializationException; import org.opendaylight.controller.sal.binding.impl.RpcProviderRegistryImpl; import org.opendaylight.controller.sal.binding.impl.RpcProviderRegistryImpl.GlobalRpcRegistrationListener; import org.opendaylight.controller.sal.binding.impl.RpcProviderRegistryImpl.RouterInstantiationListener; @@ -79,6 +77,8 @@ import org.opendaylight.yangtools.yang.common.RpcResult; import org.opendaylight.yangtools.yang.data.api.CompositeNode; import org.opendaylight.yangtools.yang.data.api.Node; import org.opendaylight.yangtools.yang.data.impl.ImmutableCompositeNode; +import org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMappingService; +import org.opendaylight.yangtools.yang.data.impl.codec.DeserializationException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -113,11 +113,11 @@ public class BindingIndependentConnector implements // private DataProviderService baDataService; - private ConcurrentMap domOpenedTransactions = new ConcurrentHashMap<>(); - private ConcurrentMap bindingOpenedTransactions = new ConcurrentHashMap<>(); + private final ConcurrentMap domOpenedTransactions = new ConcurrentHashMap<>(); + private final ConcurrentMap bindingOpenedTransactions = new ConcurrentHashMap<>(); - private BindingToDomCommitHandler bindingToDomCommitHandler = new BindingToDomCommitHandler(); - private DomToBindingCommitHandler domToBindingCommitHandler = new DomToBindingCommitHandler(); + private final BindingToDomCommitHandler bindingToDomCommitHandler = new BindingToDomCommitHandler(); + private final DomToBindingCommitHandler domToBindingCommitHandler = new DomToBindingCommitHandler(); private Registration, DataObject>> baCommitHandlerRegistration; @@ -130,7 +130,7 @@ public class BindingIndependentConnector implements // // private ListenerRegistration // bindingToDomRpcManager; - private Function, org.opendaylight.yangtools.yang.data.api.InstanceIdentifier> toDOMInstanceIdentifier = new Function, org.opendaylight.yangtools.yang.data.api.InstanceIdentifier>() { + private final Function, org.opendaylight.yangtools.yang.data.api.InstanceIdentifier> toDOMInstanceIdentifier = new Function, org.opendaylight.yangtools.yang.data.api.InstanceIdentifier>() { @Override public org.opendaylight.yangtools.yang.data.api.InstanceIdentifier apply(InstanceIdentifier input) { @@ -149,8 +149,6 @@ public class BindingIndependentConnector implements // private RpcProviderRegistryImpl baRpcRegistryImpl; - private org.opendaylight.controller.sal.dom.broker.spi.RpcRouter biRouter; - private NotificationProviderService baNotifyService; private NotificationPublishService domNotificationService; @@ -319,9 +317,6 @@ public class BindingIndependentConnector implements // 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; } } @@ -413,8 +408,8 @@ public class BindingIndependentConnector implements // private class BindingToDomTransaction implements DataCommitTransaction, DataObject> { - private DataModificationTransaction backing; - private DataModification, DataObject> modification; + private final DataModificationTransaction backing; + private final DataModification, DataObject> modification; public BindingToDomTransaction(DataModificationTransaction backing, DataModification, DataObject> modification) { @@ -491,6 +486,7 @@ public class BindingIndependentConnector implements // // FIXME: do registration based on only active commit handlers. } + @Override public org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction requestCommit( DataModification domTransaction) { Object identifier = domTransaction.getIdentifier(); @@ -587,9 +583,9 @@ public class BindingIndependentConnector implements // private final Set supportedRpcs; private final WeakReference> rpcServiceType; - private Set registrations; - private Map strategiesByQName = new HashMap<>(); - private WeakHashMap strategiesByMethod = new WeakHashMap<>(); + private final Set registrations; + private final Map strategiesByQName = new HashMap<>(); + private final WeakHashMap strategiesByMethod = new WeakHashMap<>(); public DomToBindingRpcForwarder(Class service) { this.rpcServiceType = new WeakReference>(service); @@ -771,10 +767,10 @@ public class BindingIndependentConnector implements // private class DefaultInvocationStrategy extends RpcInvocationStrategy { @SuppressWarnings("rawtypes") - private WeakReference inputClass; + private final WeakReference inputClass; @SuppressWarnings("rawtypes") - private WeakReference outputClass; + private final WeakReference outputClass; @SuppressWarnings({ "rawtypes", "unchecked" }) public DefaultInvocationStrategy(QName rpc, Method targetMethod, Class outputClass, @@ -803,10 +799,10 @@ public class BindingIndependentConnector implements // @Override public Future> forwardToDomBroker(DataObject input) { - if(biRouter != null) { + if(biRpcRegistry != null) { CompositeNode xml = mappingService.toDataDom(input); CompositeNode wrappedXml = ImmutableCompositeNode.create(rpc, ImmutableList.> of(xml)); - RpcResult result = biRouter.invokeRpc(rpc, wrappedXml); + RpcResult result = biRpcRegistry.invokeRpc(rpc, wrappedXml); Object baResultValue = null; if (result.getResult() != null) { baResultValue = mappingService.dataObjectFromDataDom(outputClass.get(), result.getResult()); @@ -825,6 +821,7 @@ public class BindingIndependentConnector implements // super(rpc, targetMethod); } + @Override public RpcResult uncheckedInvoke(RpcService rpcService, CompositeNode domInput) throws Exception { @SuppressWarnings("unchecked") Future> result = (Future>) targetMethod.invoke(rpcService); @@ -837,21 +834,21 @@ public class BindingIndependentConnector implements // return Futures.immediateFuture(null); } } - + private class NoOutputInvocationStrategy extends RpcInvocationStrategy { - + @SuppressWarnings("rawtypes") - private WeakReference inputClass; + private final WeakReference inputClass; @SuppressWarnings({ "rawtypes", "unchecked" }) - public NoOutputInvocationStrategy(QName rpc, Method targetMethod, + public NoOutputInvocationStrategy(QName rpc, Method targetMethod, Class inputClass) { super(rpc,targetMethod); this.inputClass = new WeakReference(inputClass); } - - + + @Override public RpcResult uncheckedInvoke(RpcService rpcService, CompositeNode domInput) throws Exception { DataContainer bindingInput = mappingService.dataObjectFromDataDom(inputClass.get(), domInput); @@ -865,10 +862,10 @@ public class BindingIndependentConnector implements // @Override public Future> forwardToDomBroker(DataObject input) { - if(biRouter != null) { + if(biRpcRegistry != null) { CompositeNode xml = mappingService.toDataDom(input); CompositeNode wrappedXml = ImmutableCompositeNode.create(rpc,ImmutableList.>of(xml)); - RpcResult result = biRouter.invokeRpc(rpc, wrappedXml); + RpcResult result = biRpcRegistry.invokeRpc(rpc, wrappedXml); Object baResultValue = null; RpcResult baResult = Rpcs.getRpcResult(result.isSuccessful(), null, result.getErrors()); return Futures.>immediateFuture(baResult); @@ -902,12 +899,12 @@ public class BindingIndependentConnector implements // public void setDomNotificationService(NotificationPublishService domService) { this.domNotificationService = domService; } - + private class DomToBindingNotificationForwarder implements NotificationInterestListener, NotificationListener { - private ConcurrentMap>> notifications = new ConcurrentHashMap<>(); - private Set supportedNotifications = new HashSet<>(); - + private final ConcurrentMap>> notifications = new ConcurrentHashMap<>(); + private final Set supportedNotifications = new HashSet<>(); + @Override public Set getSupportedNotifications() { return Collections.unmodifiableSet(supportedNotifications); @@ -922,7 +919,7 @@ public class BindingIndependentConnector implements // if (potentialClass != null) { final DataContainer baNotification = mappingService.dataObjectFromDataDom(potentialClass, notification); - + if (baNotification instanceof Notification) { baNotifyService.publish((Notification) baNotification); } diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/DataModificationTracker.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/DataModificationTracker.java index e89797ca2d..8278b36551 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/DataModificationTracker.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/DataModificationTracker.java @@ -13,19 +13,13 @@ import java.util.concurrent.ConcurrentMap; import org.opendaylight.controller.md.sal.common.api.data.DataModification; import org.opendaylight.yangtools.concepts.Path; -import com.google.common.util.concurrent.JdkFutureAdapters; - public final class DataModificationTracker

,D> { - ConcurrentMap> trackedTransactions = new ConcurrentHashMap<>(); - - + public void startTrackingModification(DataModification modification) { trackedTransactions.putIfAbsent(modification.getIdentifier(), modification); - - } - + public boolean containsIdentifier(Object identifier) { return trackedTransactions.containsKey(identifier); } diff --git a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/AbstractDataServiceTest.java b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/AbstractDataServiceTest.java index 7c38ff2731..6c80f4d739 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/AbstractDataServiceTest.java +++ b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/AbstractDataServiceTest.java @@ -10,12 +10,11 @@ package org.opendaylight.controller.sal.binding.test; import org.junit.After; import org.junit.Before; import org.opendaylight.controller.sal.binding.api.data.DataProviderService; -import org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMappingService; import org.opendaylight.controller.sal.binding.test.util.BindingBrokerTestFactory; import org.opendaylight.controller.sal.binding.test.util.BindingTestContext; import org.opendaylight.controller.sal.core.api.data.DataStore; import org.opendaylight.controller.sal.dom.broker.impl.DataStoreStatsWrapper; -import org.opendaylight.controller.sal.dom.broker.impl.HashMapDataStore; +import org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMappingService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/RuntimeCodeGeneratorTest.java b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/RuntimeCodeGeneratorTest.java index 76abd833e9..4afbc29842 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/RuntimeCodeGeneratorTest.java +++ b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/RuntimeCodeGeneratorTest.java @@ -7,22 +7,20 @@ */ package org.opendaylight.controller.sal.binding.test; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertSame; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; import java.util.ArrayList; import java.util.Arrays; -import java.util.HashMap; import java.util.List; -import java.util.Map; import javassist.ClassPool; import org.junit.Before; import org.junit.Test; - -import static org.opendaylight.controller.sal.binding.codegen.RuntimeCodeHelper.*; - -import org.opendaylight.controller.sal.binding.api.NotificationListener; import org.opendaylight.controller.sal.binding.api.rpc.RpcRouter; import org.opendaylight.controller.sal.binding.api.rpc.RpcRoutingTable; import org.opendaylight.controller.sal.binding.codegen.impl.RuntimeCodeGenerator; @@ -30,12 +28,10 @@ import org.opendaylight.controller.sal.binding.spi.NotificationInvokerFactory; import org.opendaylight.controller.sal.binding.spi.NotificationInvokerFactory.NotificationInvoker; import org.opendaylight.controller.sal.binding.test.mock.BarListener; import org.opendaylight.controller.sal.binding.test.mock.BarUpdate; -import org.opendaylight.controller.sal.binding.test.mock.CompositeListener; import org.opendaylight.controller.sal.binding.test.mock.FlowDelete; import org.opendaylight.controller.sal.binding.test.mock.FooListener; import org.opendaylight.controller.sal.binding.test.mock.FooService; import org.opendaylight.controller.sal.binding.test.mock.FooUpdate; -import org.opendaylight.controller.sal.binding.test.mock.InheritedContextInput; import org.opendaylight.controller.sal.binding.test.mock.ReferencableObject; import org.opendaylight.controller.sal.binding.test.mock.ReferencableObjectKey; import org.opendaylight.controller.sal.binding.test.mock.SimpleInput; @@ -47,8 +43,6 @@ import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.IdentifiableItem; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument; -import static org.mockito.Mockito.*; - public class RuntimeCodeGeneratorTest { private RuntimeCodeGenerator codeGenerator; @@ -84,7 +78,7 @@ public class RuntimeCodeGeneratorTest { NotificationInvoker invokerFoo = invokerFactory.invokerFor(fooListener); - + assertSame(fooListener,invokerFoo.getDelegate()); assertNotNull(invokerFoo.getSupportedNotifications()); assertEquals(1, invokerFoo.getSupportedNotifications().size()); diff --git a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/mock/ReferencableObjectKey.java b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/mock/ReferencableObjectKey.java index 7ab489a9f5..68d7f6cd9e 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/mock/ReferencableObjectKey.java +++ b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/mock/ReferencableObjectKey.java @@ -10,9 +10,9 @@ package org.opendaylight.controller.sal.binding.test.mock; import org.opendaylight.yangtools.yang.binding.Identifier; public class ReferencableObjectKey implements Identifier { - + private static final long serialVersionUID = 1L; final Integer value; - + public ReferencableObjectKey(Integer _value) { this.value = _value; } @@ -46,6 +46,6 @@ public class ReferencableObjectKey implements Identifier { public String toString() { return "ReferencableObjectKey [value=" + value + "]"; } - - + + } diff --git a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/util/BindingBrokerTestFactory.java b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/util/BindingBrokerTestFactory.java index 2b0865ae46..e5b57e3668 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/util/BindingBrokerTestFactory.java +++ b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/util/BindingBrokerTestFactory.java @@ -11,11 +11,6 @@ import java.util.concurrent.ExecutorService; import javassist.ClassPool; -import org.opendaylight.controller.sal.core.api.data.DataStore; -import org.opendaylight.controller.sal.dom.broker.impl.DataStoreStatsWrapper; -import org.opendaylight.controller.sal.dom.broker.impl.HashMapDataStore; -import org.opendaylight.controller.sal.dom.broker.impl.SchemaAwareDataStoreAdapter; - import com.google.common.base.Preconditions; import com.google.common.util.concurrent.ListeningExecutorService; import com.google.common.util.concurrent.MoreExecutors; @@ -27,7 +22,7 @@ public class BindingBrokerTestFactory { private ExecutorService executor; private ClassPool classPool; - + public boolean isStartWithParsedSchema() { return startWithParsedSchema; } @@ -55,7 +50,7 @@ public class BindingBrokerTestFactory { if(classPool == null) { return CLASS_POOL; } - + return classPool; } diff --git a/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/DOMCodecBug01Test.java b/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/DOMCodecBug01Test.java index ec8c8372c1..d016754385 100644 --- a/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/DOMCodecBug01Test.java +++ b/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/DOMCodecBug01Test.java @@ -7,6 +7,10 @@ */ package org.opendaylight.controller.sal.binding.test.bugfix; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -15,17 +19,10 @@ import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; - - - - - - - import org.junit.Test; import org.opendaylight.controller.md.sal.common.api.TransactionStatus; -import org.opendaylight.controller.sal.binding.test.AbstractDataServiceTest; import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction; +import org.opendaylight.controller.sal.binding.test.AbstractDataServiceTest; import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.PopMplsActionCaseBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.pop.mpls.action._case.PopMplsActionBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action; @@ -40,15 +37,13 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instru import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.apply.actions._case.ApplyActionsBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.VlanId; import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.VlanMatchBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv4MatchBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._4.match.TcpMatchBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.vlan.match.fields.VlanIdBuilder; import org.opendaylight.yangtools.yang.binding.DataObject; @@ -63,8 +58,6 @@ import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListeningExecutorService; import com.google.common.util.concurrent.MoreExecutors; -import static org.junit.Assert.*; - public class DOMCodecBug01Test extends AbstractDataServiceTest { private static final QName NODE_ID_QNAME = QName.create(Node.QNAME, "id"); @@ -182,7 +175,7 @@ public class DOMCodecBug01Test extends AbstractDataServiceTest { flow.setNode(NODE_REF); InstructionsBuilder instructions = new InstructionsBuilder(); InstructionBuilder instruction = new InstructionBuilder(); - + instruction.setOrder(10); ApplyActionsBuilder applyActions = new ApplyActionsBuilder(); List actionList = new ArrayList<>(); @@ -204,7 +197,7 @@ public class DOMCodecBug01Test extends AbstractDataServiceTest { assertNotNull(ret); assertEquals(TransactionStatus.COMMITED, ret.getResult()); } - + private void createFlow2() throws Exception { DataModificationTransaction modification = baDataService.beginTransaction(); long id = 123; @@ -215,7 +208,7 @@ public class DOMCodecBug01Test extends AbstractDataServiceTest { MatchBuilder match = new MatchBuilder(); match.setLayer4Match(new TcpMatchBuilder().build()); flow.setMatch(match.build()); - + path1 = InstanceIdentifier.builder(Flows.class).child(Flow.class, key).toInstance(); // DataObject cls = (DataObject) modification.readConfigurationData(path1); modification.putConfigurationData(path1, flow.build()); diff --git a/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/DOMCodecBug02Test.java b/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/DOMCodecBug02Test.java index 929eb66350..9d60440698 100644 --- a/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/DOMCodecBug02Test.java +++ b/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/DOMCodecBug02Test.java @@ -7,6 +7,9 @@ */ package org.opendaylight.controller.sal.binding.test.bugfix; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + import java.util.Collections; import java.util.Map; import java.util.concurrent.Callable; @@ -16,29 +19,24 @@ import java.util.concurrent.Future; import javassist.ClassPool; -import org.junit.Ignore; import org.junit.Test; import org.opendaylight.controller.md.sal.common.api.TransactionStatus; +import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction; import org.opendaylight.controller.sal.binding.test.AbstractDataServiceTest; import org.opendaylight.controller.sal.binding.test.util.BindingBrokerTestFactory; -import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.config.rev130819.flows.Flow; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; 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.NodesBuilder; +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.InstanceIdentifier; import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.common.RpcResult; -import org.opendaylight.yangtools.yang.model.api.SchemaContext; import com.google.common.util.concurrent.ListeningExecutorService; import com.google.common.util.concurrent.MoreExecutors; -import static org.junit.Assert.*; - public class DOMCodecBug02Test extends AbstractDataServiceTest { private static final QName NODE_ID_QNAME = QName.create(Node.QNAME, "id"); @@ -70,10 +68,11 @@ public class DOMCodecBug02Test extends AbstractDataServiceTest { /** * This test is ignored, till found out better way to test generation * of classes without leaking of instances from previous run - * + * * @throws Exception */ - + + @Override public void setUp() { ListeningExecutorService executor = MoreExecutors.sameThreadExecutor(); BindingBrokerTestFactory factory = new BindingBrokerTestFactory(); @@ -82,13 +81,13 @@ public class DOMCodecBug02Test extends AbstractDataServiceTest { factory.setStartWithParsedSchema(getStartWithSchema()); testContext = factory.getTestContext(); testContext.start(); - + baDataService = testContext.getBindingDataBroker(); biDataService = testContext.getDomDataBroker(); dataStore = testContext.getDomDataStore(); mappingService = testContext.getBindingToDomMappingService(); }; - + @Test public void testSchemaContextNotAvailable() throws Exception { @@ -104,11 +103,11 @@ public class DOMCodecBug02Test extends AbstractDataServiceTest { return transaction.commit(); } }); - - + + RpcResult result = future.get().get(); assertEquals(TransactionStatus.COMMITED, result.getResult()); - + Nodes nodes = checkForNodes(); assertNotNull(nodes); @@ -118,7 +117,7 @@ public class DOMCodecBug02Test extends AbstractDataServiceTest { return (Nodes) baDataService.readOperationalData(NODES_INSTANCE_ID_BA); } - + @Override protected boolean getStartWithSchema() { return false; diff --git a/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/DOMCodecBug03Test.java b/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/DOMCodecBug03Test.java index f2576e9960..6a050efb35 100644 --- a/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/DOMCodecBug03Test.java +++ b/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/DOMCodecBug03Test.java @@ -6,7 +6,11 @@ * and is available at http://www.eclipse.org/legal/epl-v10.html */ package org.opendaylight.controller.sal.binding.test.bugfix; -import java.util.Arrays; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + import java.util.Collections; import java.util.List; import java.util.Map; @@ -14,35 +18,31 @@ import java.util.Map; import org.junit.Test; import org.opendaylight.controller.md.sal.common.api.TransactionStatus; import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent; -import org.opendaylight.controller.sal.binding.test.AbstractDataServiceTest; import org.opendaylight.controller.sal.binding.api.data.DataChangeListener; import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction; +import org.opendaylight.controller.sal.binding.test.AbstractDataServiceTest; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.flow.node.SupportedActions; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.flow.node.SupportedActionsBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.flow.node.supported.actions.ActionType; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.flow.node.supported.actions.ActionTypeBuilder; +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; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.SupportType; 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.NodeConnectorId; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.SupportType; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.features.TableFeaturesBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.features.TableFeaturesKey; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.common.RpcResult; import org.opendaylight.yangtools.yang.data.api.CompositeNode; -import static org.junit.Assert.*; - public class DOMCodecBug03Test extends AbstractDataServiceTest implements DataChangeListener { private static final QName NODE_ID_QNAME = QName.create(Node.QNAME, "id"); @@ -60,15 +60,15 @@ public class DOMCodecBug03Test extends AbstractDataServiceTest implements DataCh private static final InstanceIdentifier NODE_INSTANCE_ID_BA = InstanceIdentifier// .builder(NODES_INSTANCE_ID_BA) // .child(Node.class, NODE_KEY).toInstance(); - - + + private static final InstanceIdentifier SUPPORTED_ACTIONS_INSTANCE_ID_BA = InstanceIdentifier// .builder(NODES_INSTANCE_ID_BA) // .child(Node.class, NODE_KEY) // .augmentation(FlowCapableNode.class) // .child(SupportedActions.class) .toInstance(); - + private static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier NODE_INSTANCE_ID_BI = // org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.builder() // @@ -77,35 +77,35 @@ public class DOMCodecBug03Test extends AbstractDataServiceTest implements DataCh .toInstance(); private static final QName SUPPORTED_ACTIONS_QNAME = QName.create(FlowCapableNode.QNAME, SupportedActions.QNAME.getLocalName()); - + private static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier SUPPORTED_ACTIONS_INSTANCE_ID_BI = // org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.builder() // .node(Nodes.QNAME) // .nodeWithKey(Node.QNAME, NODE_KEY_BI) // .node(SUPPORTED_ACTIONS_QNAME) // .toInstance(); - + private DataChangeEvent, DataObject> receivedChangeEvent; - - + + /** * Test for Bug 148 - * + * * @throws Exception */ @Test public void testAugmentSerialization() throws Exception { - + baDataService.registerDataChangeListener(NODES_INSTANCE_ID_BA, this); - + NodeBuilder nodeBuilder = new NodeBuilder(); nodeBuilder.setId(new NodeId(NODE_ID)); nodeBuilder.setKey(NODE_KEY); DataModificationTransaction transaction = baDataService.beginTransaction(); - - + + FlowCapableNodeBuilder fnub = new FlowCapableNodeBuilder(); fnub.setHardware("Hardware Foo"); fnub.setManufacturer("Manufacturer Foo"); @@ -116,47 +116,47 @@ public class DOMCodecBug03Test extends AbstractDataServiceTest implements DataCh nodeBuilder.addAugmentation(FlowCapableNode.class, fnu); Node original = nodeBuilder.build(); transaction.putOperationalData(NODE_INSTANCE_ID_BA, original); - + RpcResult result = transaction.commit().get(); assertEquals(TransactionStatus.COMMITED, result.getResult()); - + assertNotNull(receivedChangeEvent); - + verifyNodes((Nodes) receivedChangeEvent.getUpdatedOperationalSubtree(),original); assertBindingIndependentVersion(NODE_INSTANCE_ID_BI); Nodes nodes = checkForNodes(); verifyNodes(nodes,original); - + testAddingNodeConnector(); testNodeRemove(); } - + @Test public void testAugmentNestedSerialization() throws Exception { DataModificationTransaction transaction = baDataService.beginTransaction(); - + SupportedActionsBuilder actions = new SupportedActionsBuilder(); ActionTypeBuilder action = new ActionTypeBuilder(); action.setAction("foo-action"); action.setSupportState(SupportType.Native); List actionTypes = Collections.singletonList(action.build()); actions.setActionType(actionTypes ); - + transaction.putOperationalData(SUPPORTED_ACTIONS_INSTANCE_ID_BA, actions.build()); RpcResult putResult = transaction.commit().get(); assertNotNull(putResult); assertEquals(TransactionStatus.COMMITED, putResult.getResult()); SupportedActions readedTable = (SupportedActions) baDataService.readOperationalData(SUPPORTED_ACTIONS_INSTANCE_ID_BA); assertNotNull(readedTable); - + CompositeNode biSupportedActions = biDataService.readOperationalData(SUPPORTED_ACTIONS_INSTANCE_ID_BI); assertNotNull(biSupportedActions); - + } private void testAddingNodeConnector() throws Exception { - + NodeConnectorId ncId = new NodeConnectorId("openflow:1:bar"); NodeConnectorKey nodeKey = new NodeConnectorKey(ncId ); InstanceIdentifier ncInstanceId = InstanceIdentifier.builder(NODE_INSTANCE_ID_BA).child(NodeConnector.class, nodeKey).toInstance(); @@ -181,7 +181,7 @@ public class DOMCodecBug03Test extends AbstractDataServiceTest implements DataCh transaction.removeOperationalData(NODE_INSTANCE_ID_BA); RpcResult result = transaction.commit().get(); assertEquals(TransactionStatus.COMMITED, result.getResult()); - + Node node = (Node) baDataService.readOperationalData(NODE_INSTANCE_ID_BA); assertNull(node); } @@ -193,13 +193,13 @@ public class DOMCodecBug03Test extends AbstractDataServiceTest implements DataCh Node readedNode = nodes.getNode().get(0); assertEquals(original.getId(), readedNode.getId()); assertEquals(original.getKey(), readedNode.getKey()); - + FlowCapableNode fnu = original.getAugmentation(FlowCapableNode.class); FlowCapableNode readedAugment = readedNode.getAugmentation(FlowCapableNode.class); assertNotNull(fnu); assertEquals(fnu.getDescription(), readedAugment.getDescription()); assertEquals(fnu.getSerialNumber(), readedAugment.getSerialNumber()); - + } private void assertBindingIndependentVersion( @@ -211,7 +211,7 @@ public class DOMCodecBug03Test extends AbstractDataServiceTest implements DataCh private Nodes checkForNodes() { return (Nodes) baDataService.readOperationalData(NODES_INSTANCE_ID_BA); } - + @Override public void onDataChanged(DataChangeEvent, DataObject> change) { receivedChangeEvent = change; diff --git a/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/PutAugmentationTest.java b/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/PutAugmentationTest.java index 8003e37e4e..90fa2be211 100644 --- a/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/PutAugmentationTest.java +++ b/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/PutAugmentationTest.java @@ -6,46 +6,41 @@ * and is available at http://www.eclipse.org/legal/epl-v10.html */ package org.opendaylight.controller.sal.binding.test.bugfix; -import java.util.Arrays; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + import java.util.Collections; -import java.util.List; import java.util.Map; import org.junit.Test; import org.opendaylight.controller.md.sal.common.api.TransactionStatus; import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent; -import org.opendaylight.controller.sal.binding.test.AbstractDataServiceTest; import org.opendaylight.controller.sal.binding.api.data.DataChangeListener; import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction; +import org.opendaylight.controller.sal.binding.test.AbstractDataServiceTest; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnectorBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.flow.node.SupportedActions; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.flow.node.SupportedActionsBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.flow.node.supported.actions.ActionType; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.flow.node.supported.actions.ActionTypeBuilder; +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; 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.NodeConnectorId; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.SupportType; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.features.TableFeaturesBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.features.TableFeaturesKey; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder; import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.common.RpcResult; import org.opendaylight.yangtools.yang.data.api.CompositeNode; -import static org.junit.Assert.*; - public class PutAugmentationTest extends AbstractDataServiceTest implements DataChangeListener { private static final QName NODE_ID_QNAME = QName.create(Node.QNAME, "id"); @@ -59,49 +54,54 @@ public class PutAugmentationTest extends AbstractDataServiceTest implements Data private static final InstanceIdentifier NODES_INSTANCE_ID_BA = InstanceIdentifier.builder(Nodes.class) // .toInstance(); - private static final InstanceIdentifier NODE_INSTANCE_ID_BA = InstanceIdentifier// .builder(NODES_INSTANCE_ID_BA) // .child(Node.class, NODE_KEY).toInstance(); - - + private static final InstanceIdentifier SUPPORTED_ACTIONS_INSTANCE_ID_BA = InstanceIdentifier// .builder(NODES_INSTANCE_ID_BA) // .child(Node.class, NODE_KEY) // .augmentation(FlowCapableNode.class) // - .child(SupportedActions.class) - .toInstance(); - + .child(SupportedActions.class).toInstance(); + + private static final InstanceIdentifier ALL_FLOW_CAPABLE_NODES = InstanceIdentifier // + .builder(NODES_INSTANCE_ID_BA) // + .child(Node.class) // + .augmentation(FlowCapableNode.class) // + .build(); private static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier NODE_INSTANCE_ID_BI = // org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.builder() // .node(Nodes.QNAME) // .nodeWithKey(Node.QNAME, NODE_KEY_BI) // .toInstance(); - private static final QName SUPPORTED_ACTIONS_QNAME = QName.create(FlowCapableNode.QNAME, SupportedActions.QNAME.getLocalName()); + private static final QName SUPPORTED_ACTIONS_QNAME = QName.create(FlowCapableNode.QNAME, + SupportedActions.QNAME.getLocalName()); - private static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier SUPPORTED_ACTIONS_INSTANCE_ID_BI = // - org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.builder() // - .node(Nodes.QNAME) // - .nodeWithKey(Node.QNAME, NODE_KEY_BI) // - .node(SUPPORTED_ACTIONS_QNAME) // - .toInstance(); - - private DataChangeEvent, DataObject> receivedChangeEvent; - - - + org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.builder() // + .node(Nodes.QNAME) // + .nodeWithKey(Node.QNAME, NODE_KEY_BI) // + .node(SUPPORTED_ACTIONS_QNAME) // + .toInstance(); + private static final InstanceIdentifier FLOW_AUGMENTATION_PATH = InstanceIdentifier // + .builder(NODE_INSTANCE_ID_BA) // + .augmentation(FlowCapableNode.class) // + .build(); + + private DataChangeEvent, DataObject> lastReceivedChangeEvent; + /** * Test for Bug 148 - * + * * @throws Exception */ @Test public void putNodeAndAugmentation() throws Exception { - baDataService.registerDataChangeListener(NODES_INSTANCE_ID_BA, this); - + baDataService.registerDataChangeListener(ALL_FLOW_CAPABLE_NODES, this); + + NodeBuilder nodeBuilder = new NodeBuilder(); nodeBuilder.setId(new NodeId(NODE_ID)); nodeBuilder.setKey(NODE_KEY); @@ -109,11 +109,11 @@ public class PutAugmentationTest extends AbstractDataServiceTest implements Data baseTransaction.putOperationalData(NODE_INSTANCE_ID_BA, nodeBuilder.build()); RpcResult result = baseTransaction.commit().get(); assertEquals(TransactionStatus.COMMITED, result.getResult()); - assertNotNull(receivedChangeEvent); + Node node = (Node) baDataService.readOperationalData(NODE_INSTANCE_ID_BA); assertNotNull(node); assertEquals(NODE_KEY, node.getKey()); - + FlowCapableNodeBuilder fnub = new FlowCapableNodeBuilder(); fnub.setHardware("Hardware Foo"); fnub.setManufacturer("Manufacturer Foo"); @@ -121,14 +121,17 @@ public class PutAugmentationTest extends AbstractDataServiceTest implements Data fnub.setDescription("Description Foo"); fnub.setSoftware("JUnit emulated"); FlowCapableNode fnu = fnub.build(); - InstanceIdentifier augmentIdentifier = InstanceIdentifier.builder(NODE_INSTANCE_ID_BA).augmentation(FlowCapableNode.class).toInstance(); + InstanceIdentifier augmentIdentifier = InstanceIdentifier.builder(NODE_INSTANCE_ID_BA) + .augmentation(FlowCapableNode.class).toInstance(); DataModificationTransaction augmentedTransaction = baDataService.beginTransaction(); augmentedTransaction.putOperationalData(augmentIdentifier, fnu); - + result = augmentedTransaction.commit().get(); assertEquals(TransactionStatus.COMMITED, result.getResult()); - - + + assertNotNull(lastReceivedChangeEvent); + assertTrue(lastReceivedChangeEvent.getCreatedOperationalData().containsKey(FLOW_AUGMENTATION_PATH)); + Node augmentedNode = (Node) baDataService.readOperationalData(NODE_INSTANCE_ID_BA); assertNotNull(node); assertEquals(NODE_KEY, augmentedNode.getKey()); @@ -138,11 +141,14 @@ public class PutAugmentationTest extends AbstractDataServiceTest implements Data assertEquals(fnu.getDescription(), readedAugmentation.getDescription()); assertBindingIndependentVersion(NODE_INSTANCE_ID_BI); testNodeRemove(); + assertTrue(lastReceivedChangeEvent.getRemovedOperationalData().contains(FLOW_AUGMENTATION_PATH)); } - + @Test public void putNodeWithAugmentation() throws Exception { - + + baDataService.registerDataChangeListener(ALL_FLOW_CAPABLE_NODES, this); + NodeBuilder nodeBuilder = new NodeBuilder(); nodeBuilder.setId(new NodeId(NODE_ID)); nodeBuilder.setKey(NODE_KEY); @@ -153,42 +159,51 @@ public class PutAugmentationTest extends AbstractDataServiceTest implements Data fnub.setDescription("Description Foo"); fnub.setSoftware("JUnit emulated"); FlowCapableNode fnu = fnub.build(); - + nodeBuilder.addAugmentation(FlowCapableNode.class, fnu); DataModificationTransaction baseTransaction = baDataService.beginTransaction(); baseTransaction.putOperationalData(NODE_INSTANCE_ID_BA, nodeBuilder.build()); RpcResult result = baseTransaction.commit().get(); + + assertNotNull(lastReceivedChangeEvent); + assertTrue(lastReceivedChangeEvent.getCreatedOperationalData().containsKey(FLOW_AUGMENTATION_PATH)); + lastReceivedChangeEvent = null; assertEquals(TransactionStatus.COMMITED, result.getResult()); - - FlowCapableNode readedAugmentation = (FlowCapableNode) baDataService.readOperationalData(InstanceIdentifier.builder(NODE_INSTANCE_ID_BA).augmentation(FlowCapableNode.class).toInstance()); + + FlowCapableNode readedAugmentation = (FlowCapableNode) baDataService.readOperationalData(InstanceIdentifier + .builder(NODE_INSTANCE_ID_BA).augmentation(FlowCapableNode.class).toInstance()); assertNotNull(readedAugmentation); + assertEquals(fnu.getHardware(), readedAugmentation.getHardware()); - + testPutNodeConnectorWithAugmentation(); + lastReceivedChangeEvent = null; testNodeRemove(); + + assertTrue(lastReceivedChangeEvent.getRemovedOperationalData().contains(FLOW_AUGMENTATION_PATH)); } - private void testPutNodeConnectorWithAugmentation() throws Exception { NodeConnectorKey ncKey = new NodeConnectorKey(new NodeConnectorId("test:0:0")); InstanceIdentifier ncPath = InstanceIdentifier.builder(NODE_INSTANCE_ID_BA) - .child(NodeConnector.class, ncKey).toInstance(); + .child(NodeConnector.class, ncKey).toInstance(); InstanceIdentifier ncAugmentPath = InstanceIdentifier.builder(ncPath) - .augmentation(FlowCapableNodeConnector.class).toInstance(); - + .augmentation(FlowCapableNodeConnector.class).toInstance(); + NodeConnectorBuilder nc = new NodeConnectorBuilder(); nc.setKey(ncKey); - + FlowCapableNodeConnectorBuilder fncb = new FlowCapableNodeConnectorBuilder(); fncb.setName("Baz"); nc.addAugmentation(FlowCapableNodeConnector.class, fncb.build()); - + DataModificationTransaction baseTransaction = baDataService.beginTransaction(); baseTransaction.putOperationalData(ncPath, nc.build()); RpcResult result = baseTransaction.commit().get(); assertEquals(TransactionStatus.COMMITED, result.getResult()); - - FlowCapableNodeConnector readedAugmentation = (FlowCapableNodeConnector) baDataService.readOperationalData(ncAugmentPath); + + FlowCapableNodeConnector readedAugmentation = (FlowCapableNodeConnector) baDataService + .readOperationalData(ncAugmentPath); assertNotNull(readedAugmentation); assertEquals(fncb.getName(), readedAugmentation.getName()); } @@ -198,29 +213,28 @@ public class PutAugmentationTest extends AbstractDataServiceTest implements Data transaction.removeOperationalData(NODE_INSTANCE_ID_BA); RpcResult result = transaction.commit().get(); assertEquals(TransactionStatus.COMMITED, result.getResult()); - + Node node = (Node) baDataService.readOperationalData(NODE_INSTANCE_ID_BA); assertNull(node); } - private void verifyNodes(Nodes nodes,Node original) { + private void verifyNodes(Nodes nodes, Node original) { assertNotNull(nodes); assertNotNull(nodes.getNode()); assertEquals(1, nodes.getNode().size()); Node readedNode = nodes.getNode().get(0); assertEquals(original.getId(), readedNode.getId()); assertEquals(original.getKey(), readedNode.getKey()); - + FlowCapableNode fnu = original.getAugmentation(FlowCapableNode.class); FlowCapableNode readedAugment = readedNode.getAugmentation(FlowCapableNode.class); assertNotNull(fnu); assertEquals(fnu.getDescription(), readedAugment.getDescription()); assertEquals(fnu.getSerialNumber(), readedAugment.getSerialNumber()); - + } - private void assertBindingIndependentVersion( - org.opendaylight.yangtools.yang.data.api.InstanceIdentifier nodeId) { + private void assertBindingIndependentVersion(org.opendaylight.yangtools.yang.data.api.InstanceIdentifier nodeId) { CompositeNode node = biDataService.readOperationalData(nodeId); assertNotNull(node); } @@ -228,10 +242,10 @@ public class PutAugmentationTest extends AbstractDataServiceTest implements Data private Nodes checkForNodes() { return (Nodes) baDataService.readOperationalData(NODES_INSTANCE_ID_BA); } - + @Override public void onDataChanged(DataChangeEvent, DataObject> change) { - receivedChangeEvent = change; + lastReceivedChangeEvent = change; } } diff --git a/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/CrossBrokerMountPointTest.java b/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/CrossBrokerMountPointTest.java index ab86836f95..63094ef3cb 100644 --- a/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/CrossBrokerMountPointTest.java +++ b/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/CrossBrokerMountPointTest.java @@ -14,11 +14,8 @@ import java.math.BigInteger; import java.util.Collections; import java.util.Map; -import javax.management.Notification; - import org.junit.Before; import org.junit.Test; -import org.opendaylight.controller.md.sal.common.api.data.DataModification; import org.opendaylight.controller.md.sal.common.api.data.DataReader; import org.opendaylight.controller.sal.binding.api.mount.MountProviderInstance; import org.opendaylight.controller.sal.binding.api.mount.MountProviderService; @@ -27,11 +24,8 @@ import org.opendaylight.controller.sal.binding.test.util.BindingTestContext; import org.opendaylight.controller.sal.core.api.mount.MountProvisionInstance; import org.opendaylight.controller.sal.core.api.mount.MountProvisionService; 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.FlowKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupStatistics; import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.group.statistics.GroupStatistics; import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupId; @@ -42,14 +36,11 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey; -import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.data.api.CompositeNode; import org.opendaylight.yangtools.yang.data.impl.ImmutableCompositeNode; -import org.opendaylight.yangtools.yang.data.impl.util.CompositeNodeBuilder; -import com.google.common.collect.ImmutableMap; import com.google.common.util.concurrent.MoreExecutors; public class CrossBrokerMountPointTest { @@ -127,8 +118,8 @@ public class CrossBrokerMountPointTest { assertNotNull(bindingMountPoint); final BigInteger packetCount = BigInteger.valueOf(500L); - - + + DataReader simpleReader = new DataReader() { @Override @@ -136,7 +127,7 @@ public class CrossBrokerMountPointTest { return null; } - + @Override public CompositeNode readOperationalData(org.opendaylight.yangtools.yang.data.api.InstanceIdentifier arg0) { if (arg0.equals(GROUP_STATISTICS_ID_BI)) { @@ -153,7 +144,7 @@ public class CrossBrokerMountPointTest { }; domMountPoint.registerOperationalReader(NODE_INSTANCE_ID_BI, simpleReader); - + GroupStatistics data = (GroupStatistics) bindingMountPoint.readOperationalData(GROUP_STATISTICS_ID_BA); assertNotNull(data); assertEquals(packetCount,data.getPacketCount().getValue()); diff --git a/opendaylight/md-sal/sal-binding-it/src/main/java/org/opendaylight/controller/test/sal/binding/it/TestHelper.java b/opendaylight/md-sal/sal-binding-it/src/main/java/org/opendaylight/controller/test/sal/binding/it/TestHelper.java index 3c5efa5e3a..4e4416777b 100644 --- a/opendaylight/md-sal/sal-binding-it/src/main/java/org/opendaylight/controller/test/sal/binding/it/TestHelper.java +++ b/opendaylight/md-sal/sal-binding-it/src/main/java/org/opendaylight/controller/test/sal/binding/it/TestHelper.java @@ -10,8 +10,6 @@ package org.opendaylight.controller.test.sal.binding.it; import static org.ops4j.pax.exam.CoreOptions.frameworkProperty; import static org.ops4j.pax.exam.CoreOptions.junitBundles; import static org.ops4j.pax.exam.CoreOptions.mavenBundle; -import static org.ops4j.pax.exam.CoreOptions.repository; -import static org.ops4j.pax.exam.CoreOptions.repositories; import static org.ops4j.pax.exam.CoreOptions.systemProperty; import org.ops4j.pax.exam.Option; @@ -91,9 +89,9 @@ public class TestHelper { public static Option bindingAwareSalBundles() { return new DefaultCompositeOption( // mdSalCoreBundles(), - + mavenBundle("org.javassist", "javassist").versionAsInProject(), // // - + mavenBundle(YANGTOOLS, "yang-data-api").versionAsInProject(), // // mavenBundle(YANGTOOLS, "yang-data-impl").versionAsInProject(), // // mavenBundle(YANGTOOLS, "yang-model-api").versionAsInProject(), // // @@ -109,7 +107,7 @@ public class TestHelper { "binding-generator-spi").versionAsInProject(), // mavenBundle(YANGTOOLS, "binding-generator-impl").versionAsInProject(), mavenBundle(YANGTOOLS + ".thirdparty", "antlr4-runtime-osgi-nohead").versionAsInProject(), // // - + mavenBundle(CONTROLLER, "sal-core-api").versionAsInProject().update(), // mavenBundle(CONTROLLER, "sal-binding-api").versionAsInProject(), // // mavenBundle(CONTROLLER, "sal-binding-config").versionAsInProject(), // @@ -118,7 +116,7 @@ public class TestHelper { mavenBundle(CONTROLLER, "sal-common-util").versionAsInProject(), // // - + mavenBundle(CONTROLLER, "sal-broker-impl").versionAsInProject(), // // mavenBundle(CONTROLLER, "sal-core-spi").versionAsInProject().update(), // diff --git a/opendaylight/md-sal/sal-binding-it/src/test/java/org/opendaylight/controller/test/sal/binding/it/AbstractTest.java b/opendaylight/md-sal/sal-binding-it/src/test/java/org/opendaylight/controller/test/sal/binding/it/AbstractTest.java index cd4f8f158d..9ac94e7b89 100644 --- a/opendaylight/md-sal/sal-binding-it/src/test/java/org/opendaylight/controller/test/sal/binding/it/AbstractTest.java +++ b/opendaylight/md-sal/sal-binding-it/src/test/java/org/opendaylight/controller/test/sal/binding/it/AbstractTest.java @@ -7,21 +7,26 @@ */ package org.opendaylight.controller.test.sal.binding.it; -import static org.ops4j.pax.exam.CoreOptions.*; -import static org.opendaylight.controller.test.sal.binding.it.TestHelper.*; - -import javax.inject.Inject; - import org.junit.runner.RunWith; import org.opendaylight.controller.sal.binding.api.BindingAwareBroker; import org.ops4j.pax.exam.Configuration; import org.ops4j.pax.exam.Option; import org.ops4j.pax.exam.junit.PaxExam; -import org.ops4j.pax.exam.options.DefaultCompositeOption; import org.ops4j.pax.exam.util.Filter; -import org.ops4j.pax.exam.util.PathUtils; import org.osgi.framework.BundleContext; +import javax.inject.Inject; + +import static org.opendaylight.controller.test.sal.binding.it.TestHelper.baseModelBundles; +import static org.opendaylight.controller.test.sal.binding.it.TestHelper.bindingAwareSalBundles; +import static org.opendaylight.controller.test.sal.binding.it.TestHelper.configMinumumBundles; +import static org.opendaylight.controller.test.sal.binding.it.TestHelper.flowCapableModelBundles; +import static org.opendaylight.controller.test.sal.binding.it.TestHelper.junitAndMockitoBundles; +import static org.opendaylight.controller.test.sal.binding.it.TestHelper.mdSalCoreBundles; +import static org.ops4j.pax.exam.CoreOptions.mavenBundle; +import static org.ops4j.pax.exam.CoreOptions.options; +import static org.ops4j.pax.exam.CoreOptions.systemProperty; + @RunWith(PaxExam.class) public abstract class AbstractTest { @@ -32,7 +37,7 @@ public abstract class AbstractTest { public static final String YANGTOOLS_MODELS = "org.opendaylight.yangtools.model"; @Inject - @Filter(timeout=60*1000) + @Filter(timeout=120*1000) BindingAwareBroker broker; @Inject diff --git a/opendaylight/md-sal/sal-binding-it/src/test/java/org/opendaylight/controller/test/sal/binding/it/AbstractTestProvider.java b/opendaylight/md-sal/sal-binding-it/src/test/java/org/opendaylight/controller/test/sal/binding/it/AbstractTestProvider.java index 2aa7493e45..da47b174f1 100644 --- a/opendaylight/md-sal/sal-binding-it/src/test/java/org/opendaylight/controller/test/sal/binding/it/AbstractTestProvider.java +++ b/opendaylight/md-sal/sal-binding-it/src/test/java/org/opendaylight/controller/test/sal/binding/it/AbstractTestProvider.java @@ -11,7 +11,6 @@ import java.util.Collection; import java.util.Collections; import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ConsumerContext; -import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext; import org.opendaylight.controller.sal.binding.api.BindingAwareProvider; import org.opendaylight.yangtools.yang.binding.RpcService; diff --git a/opendaylight/md-sal/sal-binding-it/src/test/java/org/opendaylight/controller/test/sal/binding/it/NoficationTest.java b/opendaylight/md-sal/sal-binding-it/src/test/java/org/opendaylight/controller/test/sal/binding/it/NoficationTest.java index a55e395c5b..b23ceaaf15 100644 --- a/opendaylight/md-sal/sal-binding-it/src/test/java/org/opendaylight/controller/test/sal/binding/it/NoficationTest.java +++ b/opendaylight/md-sal/sal-binding-it/src/test/java/org/opendaylight/controller/test/sal/binding/it/NoficationTest.java @@ -19,7 +19,6 @@ import org.junit.Before; import org.junit.Test; import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ConsumerContext; import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext; -import org.opendaylight.controller.sal.binding.api.BindingAwareProvider.ProviderFunctionality; import org.opendaylight.controller.sal.binding.api.BindingAwareConsumer; import org.opendaylight.controller.sal.binding.api.BindingAwareProvider; import org.opendaylight.controller.sal.binding.api.NotificationProviderService; @@ -38,8 +37,8 @@ import org.opendaylight.yangtools.yang.binding.RpcService; public class NoficationTest extends AbstractTest { - private FlowListener listener1 = new FlowListener(); - private FlowListener listener2 = new FlowListener(); + private final FlowListener listener1 = new FlowListener(); + private final FlowListener listener2 = new FlowListener(); private Registration listener1Reg; private Registration listener2Reg; @@ -53,9 +52,9 @@ public class NoficationTest extends AbstractTest { @Test public void notificationTest() throws Exception { /** - * + * * The registration of the Provider 1. - * + * */ AbstractTestProvider provider1 = new AbstractTestProvider() { @Override @@ -69,10 +68,10 @@ public class NoficationTest extends AbstractTest { assertNotNull(notifyProviderService); /** - * + * * The registration of the Consumer 1. It retrieves Notification Service * from MD-SAL and registers SalFlowListener as notification listener - * + * */ BindingAwareConsumer consumer1 = new BindingAwareConsumer() { @Override @@ -97,7 +96,7 @@ public class NoficationTest extends AbstractTest { /** * Check that one notification was delivered and has correct cookie. - * + * */ assertEquals(1, listener1.addedFlows.size()); assertEquals(0, listener1.addedFlows.get(0).getCookie().intValue()); @@ -107,31 +106,31 @@ public class NoficationTest extends AbstractTest { * registered as notification listener. */ BindingAwareProvider provider = new BindingAwareProvider() { - + @Override public void onSessionInitiated(ProviderContext session) { listener2Reg = session.getSALService(NotificationProviderService.class).registerNotificationListener( listener2); } - + @Override public void onSessionInitialized(ConsumerContext session) { // TODO Auto-generated method stub - + } - + @Override public Collection getImplementations() { // TODO Auto-generated method stub return null; } - + @Override public Collection getFunctionality() { // TODO Auto-generated method stub return null; } - + }; // registerConsumer method calls onSessionInitialized method above @@ -153,19 +152,19 @@ public class NoficationTest extends AbstractTest { /** * Check that 3 notification was delivered to both listeners (first one * received 4 in total, second 3 in total). - * + * */ assertEquals(4, listener1.addedFlows.size()); assertEquals(3, listener2.addedFlows.size()); /** * The second listener is closed (unregistered) - * + * */ listener2Reg.close(); /** - * + * * The notification 5 is published */ notifyProviderService.publish(flowAdded(10)); @@ -180,7 +179,7 @@ public class NoficationTest extends AbstractTest { * Check that first consumer received 5 notifications in total, second * consumer received only three. Last notification was never received by * second consumer because its listener was unregistered. - * + * */ assertEquals(5, listener1.addedFlows.size()); assertEquals(3, listener2.addedFlows.size()); @@ -190,7 +189,7 @@ public class NoficationTest extends AbstractTest { /** * Creates instance of the type FlowAdded. Only cookie value is set. It is * used only for testing purpose. - * + * * @param i * cookie value * @return instance of the type FlowAdded @@ -202,7 +201,7 @@ public class NoficationTest extends AbstractTest { } /** - * + * * Implements * {@link org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SalFlowListener * SalFlowListener} and contains attributes which keep lists of objects of @@ -225,7 +224,7 @@ public class NoficationTest extends AbstractTest { @Override public void onFlowRemoved(FlowRemoved notification) { removedFlows.add(notification); - }; + }; @Override public void onFlowUpdated(FlowUpdated notification) { @@ -235,20 +234,20 @@ public class NoficationTest extends AbstractTest { @Override public void onSwitchFlowRemoved(SwitchFlowRemoved notification) { // TODO Auto-generated method stub - + } @Override public void onNodeErrorNotification(NodeErrorNotification notification) { // TODO Auto-generated method stub - + } @Override public void onNodeExperimenterErrorNotification( NodeExperimenterErrorNotification notification) { // TODO Auto-generated method stub - + } } diff --git a/opendaylight/md-sal/sal-binding-it/src/test/java/org/opendaylight/controller/test/sal/binding/it/RoutedServiceTest.java b/opendaylight/md-sal/sal-binding-it/src/test/java/org/opendaylight/controller/test/sal/binding/it/RoutedServiceTest.java index 8c81987301..befe703764 100644 --- a/opendaylight/md-sal/sal-binding-it/src/test/java/org/opendaylight/controller/test/sal/binding/it/RoutedServiceTest.java +++ b/opendaylight/md-sal/sal-binding-it/src/test/java/org/opendaylight/controller/test/sal/binding/it/RoutedServiceTest.java @@ -15,7 +15,6 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import java.math.BigInteger; -import java.util.concurrent.Future; import org.junit.Before; import org.junit.Test; @@ -26,9 +25,7 @@ import org.opendaylight.controller.sal.binding.api.BindingAwareConsumer; import org.opendaylight.controller.sal.binding.api.BindingAwareProvider; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowInputBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.RemoveFlowInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SalFlowService; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.UpdateFlowInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeContext; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef; @@ -36,7 +33,6 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.opendaylight.yangtools.yang.common.RpcResult; public class RoutedServiceTest extends AbstractTest { @@ -71,7 +67,7 @@ public class RoutedServiceTest extends AbstractTest { /** * Register provider 1 with first implementation of SalFlowService - * service1 - * + * */ broker.registerProvider(provider1, getBundleContext()); assertNotNull("Registration should not be null", firstReg); @@ -89,7 +85,7 @@ public class RoutedServiceTest extends AbstractTest { /** * Register provider 2 with first implementation of SalFlowService - * service2 - * + * */ broker.registerProvider(provider2, getBundleContext()); assertNotNull("Registration should not be null", firstReg); @@ -117,7 +113,7 @@ public class RoutedServiceTest extends AbstractTest { /** * Consumer creates addFlow message for node one and sends it to the * MD-SAL - * + * */ AddFlowInput addFlowFirstMessage = createSampleAddFlow(nodeOne, 1); consumerService.addFlow(addFlowFirstMessage); @@ -125,19 +121,19 @@ public class RoutedServiceTest extends AbstractTest { /** * Verifies that implementation of the first provider received the same * message from MD-SAL. - * + * */ verify(salFlowService1).addFlow(addFlowFirstMessage); /** * Verifies that second instance was not invoked with first message - * + * */ verify(salFlowService2, times(0)).addFlow(addFlowFirstMessage); /** * Provider 2 registers path of node 2 - * + * */ NodeRef nodeTwo = createNodeRef("foo:node:2"); secondReg.registerPath(NodeContext.class, nodeTwo.getValue()); @@ -154,26 +150,26 @@ public class RoutedServiceTest extends AbstractTest { /** * Verifies that second instance was invoked 3 times with second message * and first instance wasn't invoked. - * + * */ verify(salFlowService2, times(3)).addFlow(AddFlowSecondMessage); verify(salFlowService1, times(0)).addFlow(AddFlowSecondMessage); /** * Unregisteration of the path for the node one in the first provider - * + * */ firstReg.unregisterPath(NodeContext.class, nodeOne.getValue()); /** * Provider 2 registers path of node 1 - * + * */ secondReg.registerPath(NodeContext.class, nodeOne.getValue()); /** * A consumer sends third message to node 1 - * + * */ AddFlowInput AddFlowThirdMessage = createSampleAddFlow(nodeOne, 3); consumerService.addFlow(AddFlowThirdMessage); @@ -189,7 +185,7 @@ public class RoutedServiceTest extends AbstractTest { /** * Returns node reference from string which represents path - * + * * @param string * string with key(path) * @return instance of the type NodeRef @@ -204,7 +200,7 @@ public class RoutedServiceTest extends AbstractTest { /** * Creates flow AddFlowInput for which only node and cookie are set - * + * * @param node * NodeRef value * @param cookie diff --git a/opendaylight/md-sal/sal-binding-util/src/main/java/org/opendaylight/controller/md/sal/binding/util/AbstractBindingSalConsumerInstance.java b/opendaylight/md-sal/sal-binding-util/src/main/java/org/opendaylight/controller/md/sal/binding/util/AbstractBindingSalConsumerInstance.java index 0c562f5d33..77b411002b 100644 --- a/opendaylight/md-sal/sal-binding-util/src/main/java/org/opendaylight/controller/md/sal/binding/util/AbstractBindingSalConsumerInstance.java +++ b/opendaylight/md-sal/sal-binding-util/src/main/java/org/opendaylight/controller/md/sal/binding/util/AbstractBindingSalConsumerInstance.java @@ -8,20 +8,14 @@ package org.opendaylight.controller.md.sal.binding.util; import java.util.concurrent.Future; -import java.util.zip.Checksum; -import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RoutedRpcRegistration; -import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RpcRegistration; import org.opendaylight.controller.sal.binding.api.NotificationListener; import org.opendaylight.controller.sal.binding.api.NotificationService; import org.opendaylight.controller.sal.binding.api.RpcConsumerRegistry; -import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry; import org.opendaylight.controller.sal.binding.api.data.DataBrokerService; import org.opendaylight.controller.sal.binding.api.data.DataChangeListener; import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction; -import org.opendaylight.controller.sal.binding.api.mount.MountInstance; import org.opendaylight.controller.sal.common.DataStoreIdentifier; -import org.opendaylight.yangtools.concepts.Identifiable; import org.opendaylight.yangtools.concepts.ListenerRegistration; import org.opendaylight.yangtools.concepts.Registration; import org.opendaylight.yangtools.yang.binding.DataObject; @@ -54,7 +48,7 @@ public abstract class AbstractBindingSalConsumerInstance T getRpcService(Class module) { return getRpcRegistryChecked().getRpcService(module); } + @Override @Deprecated public void addNotificationListener(Class notificationType, NotificationListener listener) { getNotificationBrokerChecked().addNotificationListener(notificationType, listener); } + @Override @Deprecated public void addNotificationListener(org.opendaylight.yangtools.yang.binding.NotificationListener listener) { getNotificationBrokerChecked().addNotificationListener(listener); } + @Override @Deprecated public void removeNotificationListener(org.opendaylight.yangtools.yang.binding.NotificationListener listener) { getNotificationBrokerChecked().removeNotificationListener(listener); } + @Override @Deprecated public void removeNotificationListener(Class notificationType, NotificationListener listener) { getNotificationBrokerChecked().removeNotificationListener(notificationType, listener); } + @Override public Registration> registerNotificationListener( Class notificationType, NotificationListener listener) { return getNotificationBrokerChecked().registerNotificationListener(notificationType, listener); } + @Override public Registration registerNotificationListener( org.opendaylight.yangtools.yang.binding.NotificationListener listener) { return getNotificationBrokerChecked().registerNotificationListener(listener); } + @Override @Deprecated public T getData(DataStoreIdentifier store, Class rootType) { return getDataBrokerChecked().getData(store, rootType); } + @Override @Deprecated public T getData(DataStoreIdentifier store, T filter) { return getDataBrokerChecked().getData(store, filter); } + @Override @Deprecated public T getCandidateData(DataStoreIdentifier store, Class rootType) { return getDataBrokerChecked().getCandidateData(store, rootType); } + @Override @Deprecated public T getCandidateData(DataStoreIdentifier store, T filter) { return getDataBrokerChecked().getCandidateData(store, filter); } + @Override @Deprecated public RpcResult editCandidateData(DataStoreIdentifier store, DataRoot changeSet) { return getDataBrokerChecked().editCandidateData(store, changeSet); } + @Override @Deprecated public Future> commit(DataStoreIdentifier store) { return getDataBrokerChecked().commit(store); } + @Override @Deprecated public DataObject getData(InstanceIdentifier data) { return getDataBrokerChecked().getData(data); } + @Override @Deprecated public DataObject getConfigurationData(InstanceIdentifier data) { return getDataBrokerChecked().getConfigurationData(data); } + @Override public DataModificationTransaction beginTransaction() { return getDataBrokerChecked().beginTransaction(); } + @Override @Deprecated public void registerChangeListener(InstanceIdentifier path, DataChangeListener changeListener) { getDataBrokerChecked().registerChangeListener(path, changeListener); } + @Override @Deprecated public void unregisterChangeListener(InstanceIdentifier path, DataChangeListener changeListener) { getDataBrokerChecked().unregisterChangeListener(path, changeListener); } + @Override @Deprecated public DataObject readConfigurationData(InstanceIdentifier path) { return getDataBrokerChecked().readConfigurationData(path); } + @Override public DataObject readOperationalData(InstanceIdentifier path) { return getDataBrokerChecked().readOperationalData(path); } + @Override @Deprecated public ListenerRegistration registerDataChangeListener( InstanceIdentifier path, DataChangeListener listener) { diff --git a/opendaylight/md-sal/sal-binding-util/src/main/java/org/opendaylight/controller/md/sal/binding/util/AbstractBindingSalProviderInstance.java b/opendaylight/md-sal/sal-binding-util/src/main/java/org/opendaylight/controller/md/sal/binding/util/AbstractBindingSalProviderInstance.java index c7d6640ce1..efa02e0b30 100644 --- a/opendaylight/md-sal/sal-binding-util/src/main/java/org/opendaylight/controller/md/sal/binding/util/AbstractBindingSalProviderInstance.java +++ b/opendaylight/md-sal/sal-binding-util/src/main/java/org/opendaylight/controller/md/sal/binding/util/AbstractBindingSalProviderInstance.java @@ -19,7 +19,6 @@ import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RpcRegistr import org.opendaylight.controller.sal.binding.api.NotificationProviderService; import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry; import org.opendaylight.controller.sal.binding.api.data.DataProviderService; -import org.opendaylight.controller.sal.binding.api.mount.MountProviderInstance; import org.opendaylight.controller.sal.binding.api.rpc.RpcContextIdentifier; import org.opendaylight.yangtools.concepts.ListenerRegistration; import org.opendaylight.yangtools.concepts.Registration; @@ -99,7 +98,7 @@ public abstract class AbstractBindingSalProviderInstance registerInterestListener( NotificationInterestListener interestListener) { diff --git a/opendaylight/md-sal/sal-binding-util/src/main/java/org/opendaylight/controller/md/sal/binding/util/BindingContextUtils.java b/opendaylight/md-sal/sal-binding-util/src/main/java/org/opendaylight/controller/md/sal/binding/util/BindingContextUtils.java index d164f82222..dc22891b47 100644 --- a/opendaylight/md-sal/sal-binding-util/src/main/java/org/opendaylight/controller/md/sal/binding/util/BindingContextUtils.java +++ b/opendaylight/md-sal/sal-binding-util/src/main/java/org/opendaylight/controller/md/sal/binding/util/BindingContextUtils.java @@ -7,26 +7,24 @@ */ package org.opendaylight.controller.md.sal.binding.util; -import java.awt.image.SinglePixelPackedSampleModel; +import static com.google.common.base.Preconditions.checkNotNull; import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener; import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ConsumerContext; import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext; import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RoutedRpcRegistration; import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RpcRegistration; +import org.opendaylight.controller.sal.binding.api.BindingAwareConsumer; import org.opendaylight.controller.sal.binding.api.BindingAwareProvider; import org.opendaylight.controller.sal.binding.api.BindingAwareProvider.ProviderFunctionality; -import org.opendaylight.controller.sal.binding.api.rpc.RpcContextIdentifier; -import org.opendaylight.controller.sal.binding.api.BindingAwareConsumer; import org.opendaylight.controller.sal.binding.api.BindingAwareService; import org.opendaylight.controller.sal.binding.api.RpcConsumerRegistry; import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry; +import org.opendaylight.controller.sal.binding.api.rpc.RpcContextIdentifier; import org.opendaylight.yangtools.concepts.ListenerRegistration; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.opendaylight.yangtools.yang.binding.RpcService; -import static com.google.common.base.Preconditions.*; - import com.google.common.collect.ClassToInstanceMap; import com.google.common.collect.MutableClassToInstanceMap; @@ -38,7 +36,7 @@ public class BindingContextUtils { checkNotNull(serviceProvider,"Service map should not be null"); return new SingleConsumerContextImpl(serviceProvider); } - + public static ProviderContext createProviderContext(BindingAwareProvider provider, ClassToInstanceMap serviceProvider) { checkNotNull(provider,"Provider should not be null"); @@ -52,7 +50,7 @@ public class BindingContextUtils { consumer.onSessionInitialized(context); return context; } - + public static ProviderContext createProviderContextAndInitialize(BindingAwareProvider provider, ClassToInstanceMap serviceProvider) { ProviderContext context = createProviderContext(provider, serviceProvider); @@ -64,9 +62,9 @@ public class BindingContextUtils { // FIXME: Create Proxy return instance; } - + private static class SingleConsumerContextImpl implements ConsumerContext, AutoCloseable { - + private ClassToInstanceMap alreadyRetrievedServices; private ClassToInstanceMap serviceProvider; @@ -79,7 +77,7 @@ public class BindingContextUtils { public final T getRpcService(Class module) { return getSALService(RpcConsumerRegistry.class).getRpcService(module); } - + @Override public final T getSALService(Class service) { checkNotNull(service,"Service class should not be null."); @@ -89,7 +87,7 @@ public class BindingContextUtils { } return tryToRetrieveSalService(service); } - + private synchronized T tryToRetrieveSalService(Class service) { final T potential = alreadyRetrievedServices.getInstance(service); if(potential != null) { @@ -103,44 +101,44 @@ public class BindingContextUtils { alreadyRetrievedServices.put(service, retrieved); return retrieved; } - + @Override public final void close() throws Exception { alreadyRetrievedServices = null; serviceProvider = null; } } - + private static class SingleProviderContextImpl extends SingleConsumerContextImpl implements ProviderContext { public SingleProviderContextImpl(ClassToInstanceMap serviceProvider) { super(serviceProvider); } - + @Override public >> ListenerRegistration registerRouteChangeListener( L listener) { return getSALService(RpcProviderRegistry.class).registerRouteChangeListener(listener); } - + @Override public RoutedRpcRegistration addRoutedRpcImplementation(Class type, T implementation) throws IllegalStateException { return getSALService(RpcProviderRegistry.class).addRoutedRpcImplementation(type, implementation); } - + @Override public RpcRegistration addRpcImplementation(Class type, T implementation) throws IllegalStateException { return getSALService(RpcProviderRegistry.class).addRpcImplementation(type, implementation); } - + @Deprecated @Override public void registerFunctionality(ProviderFunctionality functionality) { // NOOP } - + @Deprecated @Override public void unregisterFunctionality(ProviderFunctionality functionality) { diff --git a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/TransactionStatus.java b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/TransactionStatus.java index 92ff55175c..a8989c4ce8 100644 --- a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/TransactionStatus.java +++ b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/TransactionStatus.java @@ -8,9 +8,26 @@ 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, } diff --git a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataChangePublisher.java b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataChangePublisher.java index 1700411df8..66645e5538 100644 --- a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataChangePublisher.java +++ b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataChangePublisher.java @@ -9,10 +9,9 @@ package org.opendaylight.controller.md.sal.common.api.data; import org.opendaylight.yangtools.concepts.ListenerRegistration; + // 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.Registration; - public interface DataChangePublisher

*/,D, L extends DataChangeListener> { ListenerRegistration registerDataChangeListener(P path, L listener); diff --git a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataModification.java b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataModification.java index 29ba192ba8..00db6064aa 100644 --- a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataModification.java +++ b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataModification.java @@ -7,20 +7,18 @@ */ package org.opendaylight.controller.md.sal.common.api.data; -import java.util.Map; -import java.util.Set; import java.util.concurrent.Future; import org.opendaylight.controller.md.sal.common.api.TransactionStatus; -// 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.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

*/, D> extends DataChange, DataReader { /** * Returns transaction identifier - * + * * @return Transaction identifier */ Object getIdentifier(); @@ -28,9 +26,9 @@ public interface DataModification

*/, D> extends DataChange< TransactionStatus getStatus(); /** - * + * * @deprecated Use {@link #putOperationalData(Object, Object)} instead. - * + * * @param path * @param data */ @@ -81,7 +79,7 @@ public interface DataModification

*/, D> extends DataChange< /** * @deprecated Use {@link #removeOperationalData(Object)} - * + * * @param path */ @Deprecated @@ -93,18 +91,18 @@ public interface DataModification

*/, D> extends DataChange< /** * Initiates a two-phase commit of modification. - * + * *

* The successful commit changes the state of the system and may affect * several components. - * + * *

* The effects of successful commit of data are described in the * specifications and YANG models describing the Provider components of * controller. It is assumed that Consumer has an understanding of this * changes. - * - * + * + * * @see DataCommitHandler for further information how two-phase commit is * processed. * @param store diff --git a/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/ListenerRegistry.java b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/ListenerRegistry.java index fed75f72be..f337b5509e 100644 --- a/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/ListenerRegistry.java +++ b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/ListenerRegistry.java @@ -7,13 +7,12 @@ */ package org.opendaylight.controller.md.sal.common.impl; +import static com.google.common.base.Preconditions.checkNotNull; + import java.util.Collections; import java.util.EventListener; import java.util.HashSet; import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; - -import static com.google.common.base.Preconditions.*; import org.opendaylight.yangtools.concepts.AbstractObjectRegistration; import org.opendaylight.yangtools.concepts.ListenerRegistration; @@ -32,15 +31,15 @@ public class ListenerRegistry { return unmodifiableView; } - + public ListenerRegistration register(T listener) { checkNotNull(listener, "Listener should not be null."); ListenerRegistrationImpl ret = new ListenerRegistrationImpl(listener); listeners.add(ret); return ret; } - - + + @SuppressWarnings("rawtypes") private void remove(ListenerRegistrationImpl registration) { listeners.remove(registration); diff --git a/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/routing/RoutingUtils.java b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/routing/RoutingUtils.java index bfa4f36c18..274f084f01 100644 --- a/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/routing/RoutingUtils.java +++ b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/routing/RoutingUtils.java @@ -42,7 +42,7 @@ public class RoutingUtils { private final Map> removal; private final Map> announcement; - public RouteChangeImpl(ImmutableMap> removal, ImmutableMap> announcement) { + public RouteChangeImpl(ImmutableMap> announcement, ImmutableMap> removal) { super(); this.removal = removal; this.announcement = announcement; diff --git a/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/AbstractDataBroker.java b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/AbstractDataBroker.java new file mode 100644 index 0000000000..bfffb594cb --- /dev/null +++ b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/AbstractDataBroker.java @@ -0,0 +1,441 @@ +/** + * 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.sal.common.impl.service; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Future; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +import org.eclipse.xtext.xbase.lib.Exceptions; +import org.opendaylight.controller.md.sal.common.api.RegistrationListener; +import org.opendaylight.controller.md.sal.common.api.TransactionStatus; +import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent; +import org.opendaylight.controller.md.sal.common.api.data.DataChangeListener; +import org.opendaylight.controller.md.sal.common.api.data.DataChangePublisher; +import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler; +import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandlerRegistration; +import org.opendaylight.controller.md.sal.common.api.data.DataModificationTransactionFactory; +import org.opendaylight.controller.md.sal.common.api.data.DataProvisionService; +import org.opendaylight.controller.md.sal.common.api.data.DataReader; +import org.opendaylight.controller.md.sal.common.impl.routing.AbstractDataReadRouter; +import org.opendaylight.yangtools.concepts.AbstractObjectRegistration; +import org.opendaylight.yangtools.concepts.CompositeObjectRegistration; +import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.opendaylight.yangtools.concepts.Path; +import org.opendaylight.yangtools.concepts.Registration; +import org.opendaylight.yangtools.concepts.util.ListenerRegistry; +import org.opendaylight.yangtools.yang.common.RpcResult; +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.collect.FluentIterable; +import com.google.common.collect.HashMultimap; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Multimap; +import com.google.common.collect.Multimaps; +import com.google.common.util.concurrent.MoreExecutors; + +public abstract class AbstractDataBroker

, D extends Object, DCL extends DataChangeListener> + implements DataModificationTransactionFactory, DataReader, DataChangePublisher, + DataProvisionService { + private final static Logger LOG = LoggerFactory.getLogger(AbstractDataBroker.class); + + private ExecutorService executor; + + public ExecutorService getExecutor() { + return this.executor; + } + + public void setExecutor(final ExecutorService executor) { + this.executor = executor; + } + + private ExecutorService notificationExecutor = MoreExecutors.sameThreadExecutor(); + + public ExecutorService getNotificationExecutor() { + return this.notificationExecutor; + } + + public void setNotificationExecutor(final ExecutorService notificationExecutor) { + this.notificationExecutor = notificationExecutor; + } + + private AbstractDataReadRouter dataReadRouter; + + private final AtomicLong submittedTransactionsCount = new AtomicLong(); + + private final AtomicLong failedTransactionsCount = new AtomicLong(); + + private final AtomicLong finishedTransactionsCount = new AtomicLong(); + + public AbstractDataReadRouter getDataReadRouter() { + return this.dataReadRouter; + } + + public void setDataReadRouter(final AbstractDataReadRouter dataReadRouter) { + this.dataReadRouter = dataReadRouter; + } + + public AtomicLong getSubmittedTransactionsCount() { + return this.submittedTransactionsCount; + } + + public AtomicLong getFailedTransactionsCount() { + return this.failedTransactionsCount; + } + + public AtomicLong getFinishedTransactionsCount() { + return this.finishedTransactionsCount; + } + + private final Multimap> listeners = Multimaps + .synchronizedSetMultimap(HashMultimap.> create()); + + private final Multimap> commitHandlers = Multimaps + .synchronizedSetMultimap(HashMultimap.> create()); + + private final Lock registrationLock = new ReentrantLock(); + + private final ListenerRegistry>> commitHandlerRegistrationListeners = new ListenerRegistry>>(); + + public AbstractDataBroker() { + } + + protected ImmutableList> affectedCommitHandlers(final Set

paths) { + final Callable>> _function = new Callable>>() { + @Override + public ImmutableList> call() throws Exception { + Map>> _asMap = commitHandlers.asMap(); + Set>>> _entrySet = _asMap.entrySet(); + FluentIterable>>> _from = FluentIterable + .>>> from(_entrySet); + final Predicate>>> _function = new Predicate>>>() { + @Override + public boolean apply(final Entry>> it) { + P _key = it.getKey(); + boolean _isAffectedBy = isAffectedBy(_key, paths); + return _isAffectedBy; + } + }; + FluentIterable>>> _filter = _from + .filter(_function); + final Function>>, Collection>> _function_1 = new Function>>, Collection>>() { + @Override + public Collection> apply( + final Entry>> it) { + Collection> _value = it.getValue(); + return _value; + } + }; + FluentIterable> _transformAndConcat = _filter + .> transformAndConcat(_function_1); + final Function, DataCommitHandler> _function_2 = new Function, DataCommitHandler>() { + @Override + public DataCommitHandler apply(final DataCommitHandlerRegistrationImpl it) { + DataCommitHandler _instance = it.getInstance(); + return _instance; + } + }; + FluentIterable> _transform = _transformAndConcat + .> transform(_function_2); + return _transform.toList(); + } + }; + return AbstractDataBroker.>> withLock(this.registrationLock, _function); + } + + protected ImmutableList> probablyAffectedCommitHandlers(final HashSet

paths) { + final Callable>> _function = new Callable>>() { + @Override + public ImmutableList> call() throws Exception { + Map>> _asMap = commitHandlers.asMap(); + Set>>> _entrySet = _asMap.entrySet(); + FluentIterable>>> _from = FluentIterable + .>>> from(_entrySet); + final Predicate>>> _function = new Predicate>>>() { + @Override + public boolean apply(final Entry>> it) { + P _key = it.getKey(); + boolean _isProbablyAffectedBy = isProbablyAffectedBy(_key, paths); + return _isProbablyAffectedBy; + } + }; + FluentIterable>>> _filter = _from + .filter(_function); + final Function>>, Collection>> _function_1 = new Function>>, Collection>>() { + @Override + public Collection> apply( + final Entry>> it) { + Collection> _value = it.getValue(); + return _value; + } + }; + FluentIterable> _transformAndConcat = _filter + .> transformAndConcat(_function_1); + final Function, DataCommitHandler> _function_2 = new Function, DataCommitHandler>() { + @Override + public DataCommitHandler apply(final DataCommitHandlerRegistrationImpl it) { + DataCommitHandler _instance = it.getInstance(); + return _instance; + } + }; + FluentIterable> _transform = _transformAndConcat + .> transform(_function_2); + return _transform.toList(); + } + }; + return AbstractDataBroker.>> withLock(this.registrationLock, _function); + } + + protected Map deepGetBySubpath(final Map dataSet, final P path) { + return Collections. emptyMap(); + } + + @Override + public final D readConfigurationData(final P path) { + AbstractDataReadRouter _dataReadRouter = this.getDataReadRouter(); + return _dataReadRouter.readConfigurationData(path); + } + + @Override + public final D readOperationalData(final P path) { + AbstractDataReadRouter _dataReadRouter = this.getDataReadRouter(); + return _dataReadRouter.readOperationalData(path); + } + + private static T withLock(final Lock lock, final Callable method) { + lock.lock(); + try { + return method.call(); + } catch (Exception e) { + throw Exceptions.sneakyThrow(e); + } finally { + lock.unlock(); + } + } + + @Override + public final Registration> registerCommitHandler(final P path, + final DataCommitHandler commitHandler) { + synchronized (commitHandler) { + final DataCommitHandlerRegistrationImpl registration = new DataCommitHandlerRegistrationImpl( + path, commitHandler, this); + commitHandlers.put(path, registration); + LOG.trace("Registering Commit Handler {} for path: {}", commitHandler, path); + for (final ListenerRegistration>> listener : commitHandlerRegistrationListeners) { + try { + listener.getInstance().onRegister(registration); + } catch (Exception e) { + LOG.error("Unexpected exception in listener {} during invoking onRegister", listener.getInstance(), + e); + } + } + return registration; + } + } + + @Override + public final ListenerRegistration registerDataChangeListener(final P path, final DCL listener) { + synchronized (listeners) { + final DataChangeListenerRegistration reg = new DataChangeListenerRegistration(path, + listener, AbstractDataBroker.this); + listeners.put(path, reg); + final D initialConfig = getDataReadRouter().readConfigurationData(path); + final D initialOperational = getDataReadRouter().readOperationalData(path); + final DataChangeEvent event = createInitialListenerEvent(path, initialConfig, initialOperational); + listener.onDataChanged(event); + return reg; + } + } + + public final CompositeObjectRegistration> registerDataReader(final P path, + final DataReader reader) { + + final Registration> confReg = getDataReadRouter().registerConfigurationReader(path, reader); + final Registration> dataReg = getDataReadRouter().registerOperationalReader(path, reader); + return new CompositeObjectRegistration>(reader, Arrays.asList(confReg, dataReg)); + } + + @Override + public ListenerRegistration>> registerCommitHandlerListener( + final RegistrationListener> commitHandlerListener) { + final ListenerRegistration>> ret = this.commitHandlerRegistrationListeners + .register(commitHandlerListener); + return ret; + } + + protected DataChangeEvent createInitialListenerEvent(final P path, final D initialConfig, + final D initialOperational) { + InitialDataChangeEventImpl _initialDataChangeEventImpl = new InitialDataChangeEventImpl( + initialConfig, initialOperational); + return _initialDataChangeEventImpl; + } + + protected final void removeListener(final DataChangeListenerRegistration registration) { + synchronized (listeners) { + listeners.remove(registration.getPath(), registration); + } + } + + protected final void removeCommitHandler(final DataCommitHandlerRegistrationImpl registration) { + synchronized (commitHandlers) { + + commitHandlers.remove(registration.getPath(), registration); + LOG.trace("Removing Commit Handler {} for path: {}", registration.getInstance(), registration.getPath()); + for (final ListenerRegistration>> listener : commitHandlerRegistrationListeners) { + try { + listener.getInstance().onUnregister(registration); + } catch (Exception e) { + LOG.error("Unexpected exception in listener {} during invoking onUnregister", + listener.getInstance(), e); + } + } + } + + } + + protected final Collection>> getActiveCommitHandlers() { + return commitHandlers.entries(); + } + + protected ImmutableList> affectedListeners(final Set

paths) { + + synchronized (listeners) { + return FluentIterable // + .from(listeners.asMap().entrySet()) // + .filter(new Predicate>>>() { + @Override + public boolean apply(final Entry>> it) { + return isAffectedBy(it.getKey(), paths); + } + }) // + .transform( + new Function>>, ListenerStateCapture>() { + @Override + public ListenerStateCapture apply( + final Entry>> it) { + return new ListenerStateCapture(it.getKey(), it.getValue(), + createContainsPredicate(it.getKey())); + } + }) // + .toList(); + } + } + + protected ImmutableList> probablyAffectedListeners(final Set

paths) { + synchronized (listeners) { + return FluentIterable // + .from(listeners.asMap().entrySet()) // + .filter(new Predicate>>>() { + @Override + public boolean apply(final Entry>> it) { + return isProbablyAffectedBy(it.getKey(), paths); + } + }) // + .transform( + new Function>>, ListenerStateCapture>() { + @Override + public ListenerStateCapture apply( + final Entry>> it) { + return new ListenerStateCapture(it.getKey(), it.getValue(), + createIsContainedPredicate(it.getKey())); + } + }) // + .toList(); + } + } + + protected Predicate

createContainsPredicate(final P key) { + return new Predicate

() { + @Override + public boolean apply(final P other) { + return key.contains(other); + } + }; + } + + protected Predicate

createIsContainedPredicate(final P key) { + return new Predicate

() { + @Override + public boolean apply(final P other) { + return other.contains(key); + } + }; + } + + protected boolean isAffectedBy(final P key, final Set

paths) { + final Predicate

contains = this.createContainsPredicate(key); + if (paths.contains(key)) { + return true; + } + for (final P path : paths) { + if (contains.apply(path)) { + return true; + } + } + return false; + } + + protected boolean isProbablyAffectedBy(final P key, final Set

paths) { + final Predicate

isContained = this.createIsContainedPredicate(key); + for (final P path : paths) { + if (isContained.apply(path)) { + return true; + } + } + return false; + } + + final Future> commit(final AbstractDataTransaction transaction) { + Preconditions.checkNotNull(transaction); + transaction.changeStatus(TransactionStatus.SUBMITED); + final TwoPhaseCommit task = new TwoPhaseCommit(transaction, this); + ; + this.getSubmittedTransactionsCount().getAndIncrement(); + return this.getExecutor().submit(task); + } + + private static class DataCommitHandlerRegistrationImpl

, D extends Object> // + extends AbstractObjectRegistration> // + implements DataCommitHandlerRegistration { + + private AbstractDataBroker dataBroker; + private final P path; + + @Override + public P getPath() { + return this.path; + } + + public DataCommitHandlerRegistrationImpl(final P path, final DataCommitHandler instance, + final AbstractDataBroker broker) { + super(instance); + this.dataBroker = broker; + this.path = path; + } + + @Override + protected void removeRegistration() { + this.dataBroker.removeCommitHandler(this); + this.dataBroker = null; + } + } +} diff --git a/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/AbstractDataBroker.xtend b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/AbstractDataBroker.xtend deleted file mode 100644 index 2c3b0188f4..0000000000 --- a/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/AbstractDataBroker.xtend +++ /dev/null @@ -1,441 +0,0 @@ -/* - * 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.sal.common.impl.service - -import com.google.common.collect.FluentIterable -import com.google.common.collect.HashMultimap -import com.google.common.collect.ImmutableList -import com.google.common.collect.Multimap -import java.util.ArrayList -import java.util.Arrays -import java.util.Collection -import java.util.Collections -import java.util.HashSet -import java.util.List -import java.util.Set -import java.util.concurrent.Callable -import java.util.concurrent.ExecutorService -import java.util.concurrent.Future -import java.util.concurrent.atomic.AtomicLong -import org.opendaylight.controller.md.sal.common.api.RegistrationListener -import org.opendaylight.controller.md.sal.common.api.TransactionStatus -import org.opendaylight.controller.md.sal.common.api.data.DataChangeListener -import org.opendaylight.controller.md.sal.common.api.data.DataChangePublisher -import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler -import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction -import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandlerRegistration -import org.opendaylight.controller.md.sal.common.api.data.DataModificationTransactionFactory -import org.opendaylight.controller.md.sal.common.api.data.DataProvisionService -import org.opendaylight.controller.md.sal.common.api.data.DataReader -import org.opendaylight.controller.md.sal.common.impl.AbstractDataModification -import org.opendaylight.controller.md.sal.common.impl.routing.AbstractDataReadRouter -import org.opendaylight.controller.sal.common.util.Rpcs -import org.opendaylight.yangtools.concepts.AbstractObjectRegistration -import org.opendaylight.yangtools.concepts.CompositeObjectRegistration -import org.opendaylight.yangtools.concepts.ListenerRegistration -import org.opendaylight.yangtools.concepts.Path -import org.opendaylight.yangtools.concepts.util.ListenerRegistry -import org.opendaylight.yangtools.yang.common.RpcResult -import org.slf4j.LoggerFactory - -import static com.google.common.base.Preconditions.* import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent -import com.google.common.collect.Multimaps -import java.util.concurrent.locks.Lock -import java.util.concurrent.locks.ReentrantLock - -abstract class AbstractDataBroker

, D, DCL extends DataChangeListener> implements DataModificationTransactionFactory, // -DataReader, // -DataChangePublisher, // -DataProvisionService { - - private static val LOG = LoggerFactory.getLogger(AbstractDataBroker); - - @Property - var ExecutorService executor; - - @Property - var AbstractDataReadRouter dataReadRouter; - - @Property - private val AtomicLong submittedTransactionsCount = new AtomicLong; - - @Property - private val AtomicLong failedTransactionsCount = new AtomicLong - - @Property - private val AtomicLong finishedTransactionsCount = new AtomicLong - - Multimap> listeners = Multimaps.synchronizedSetMultimap(HashMultimap.create()); - Multimap> commitHandlers = Multimaps.synchronizedSetMultimap(HashMultimap.create()); - - private val Lock registrationLock = new ReentrantLock; - - val ListenerRegistry>> commitHandlerRegistrationListeners = new ListenerRegistry(); - public new() { - } - - protected def /*Iterator>,D>>*/ affectedCommitHandlers( - HashSet

paths) { - return withLock(registrationLock) [| - return FluentIterable.from(commitHandlers.asMap.entrySet).filter[key.isAffectedBy(paths)] // - .transformAndConcat[value] // - .transform[instance].toList() - ] - } - - override final readConfigurationData(P path) { - return dataReadRouter.readConfigurationData(path); - } - - override final readOperationalData(P path) { - return dataReadRouter.readOperationalData(path); - } - - private static def withLock(Lock lock,Callable method) { - lock.lock - try { - return method.call - } finally { - lock.unlock - } - } - - override final registerCommitHandler(P path, DataCommitHandler commitHandler) { - return withLock(registrationLock) [| - val registration = new DataCommitHandlerRegistrationImpl(path, commitHandler, this); - commitHandlers.put(path, registration) - LOG.trace("Registering Commit Handler {} for path: {}",commitHandler,path); - for(listener : commitHandlerRegistrationListeners) { - try { - listener.instance.onRegister(registration); - } catch (Exception e) { - LOG.error("Unexpected exception in listener {} during invoking onRegister",listener.instance,e); - } - } - return registration; - ] - } - - override final def registerDataChangeListener(P path, DCL listener) { - return withLock(registrationLock) [| - val reg = new DataChangeListenerRegistration(path, listener, this); - listeners.put(path, reg); - val initialConfig = dataReadRouter.readConfigurationData(path); - val initialOperational = dataReadRouter.readOperationalData(path); - val event = createInitialListenerEvent(path,initialConfig,initialOperational); - listener.onDataChanged(event); - return reg; - ] - } - - final def registerDataReader(P path, DataReader reader) { - return withLock(registrationLock) [| - val confReg = dataReadRouter.registerConfigurationReader(path, reader); - val dataReg = dataReadRouter.registerOperationalReader(path, reader); - - return new CompositeObjectRegistration(reader, Arrays.asList(confReg, dataReg)); - ] - } - - override registerCommitHandlerListener(RegistrationListener> commitHandlerListener) { - val ret = commitHandlerRegistrationListeners.register(commitHandlerListener); - return ret; - } - - protected def DataChangeEvent createInitialListenerEvent(P path,D initialConfig,D initialOperational) { - return new InitialDataChangeEventImpl(initialConfig,initialOperational); - - } - - protected final def removeListener(DataChangeListenerRegistration registration) { - return withLock(registrationLock) [| - listeners.remove(registration.path, registration); - ] - } - - protected final def removeCommitHandler(DataCommitHandlerRegistrationImpl registration) { - return withLock(registrationLock) [| - commitHandlers.remove(registration.path, registration); - LOG.trace("Removing Commit Handler {} for path: {}",registration.instance,registration.path); - for(listener : commitHandlerRegistrationListeners) { - try { - listener.instance.onUnregister(registration); - } catch (Exception e) { - LOG.error("Unexpected exception in listener {} during invoking onUnregister",listener.instance,e); - } - } - return null; - ] - } - - protected final def getActiveCommitHandlers() { - return commitHandlers.entries; - } - - protected def /*Iterator>,D>>*/ affectedListenersWithInitialState( - HashSet

paths) { - return withLock(registrationLock) [| - return FluentIterable.from(listeners.asMap.entrySet).filter[key.isAffectedBy(paths)].transform [ - val operationalState = readOperationalData(key) - val configurationState = readConfigurationData(key) - return new ListenerStateCapture(key, value, operationalState, configurationState) - ].toList() - ] - } - - protected def boolean isAffectedBy(P key, Set

paths) { - if (paths.contains(key)) { - return true; - } - for (path : paths) { - if (key.contains(path)) { - return true; - } - } - - return false; - } - - package final def Future> commit(AbstractDataTransaction transaction) { - checkNotNull(transaction); - transaction.changeStatus(TransactionStatus.SUBMITED); - val task = new TwoPhaseCommit(transaction, this); - submittedTransactionsCount.andIncrement; - return executor.submit(task); - } - -} - -@Data -package class ListenerStateCapture

, D, DCL extends DataChangeListener> { - - @Property - P path; - - @Property - Collection> listeners; - - @Property - D initialOperationalState; - - @Property - D initialConfigurationState; -} - -package class DataChangeListenerRegistration

, D, DCL extends DataChangeListener> extends AbstractObjectRegistration implements ListenerRegistration { - - AbstractDataBroker dataBroker; - - @Property - val P path; - - new(P path, DCL instance, AbstractDataBroker broker) { - super(instance) - dataBroker = broker; - _path = path; - } - - override protected removeRegistration() { - dataBroker.removeListener(this); - dataBroker = null; - } - -} - -package class DataCommitHandlerRegistrationImpl

, D> // -extends AbstractObjectRegistration> // -implements DataCommitHandlerRegistration { - - AbstractDataBroker dataBroker; - - @Property - val P path; - - new(P path, DataCommitHandler instance, AbstractDataBroker broker) { - super(instance) - dataBroker = broker; - _path = path; - } - - override protected removeRegistration() { - dataBroker.removeCommitHandler(this); - dataBroker = null; - } -} - -package class TwoPhaseCommit

, D, DCL extends DataChangeListener> implements Callable> { - - private static val log = LoggerFactory.getLogger(TwoPhaseCommit); - - val AbstractDataTransaction transaction; - val AbstractDataBroker dataBroker; - - new(AbstractDataTransaction transaction, AbstractDataBroker broker) { - this.transaction = transaction; - this.dataBroker = broker; - } - - override call() throws Exception { - - // get affected paths - val affectedPaths = new HashSet

(); - - affectedPaths.addAll(transaction.createdConfigurationData.keySet); - affectedPaths.addAll(transaction.updatedConfigurationData.keySet); - affectedPaths.addAll(transaction.removedConfigurationData); - - affectedPaths.addAll(transaction.createdOperationalData.keySet); - affectedPaths.addAll(transaction.updatedOperationalData.keySet); - affectedPaths.addAll(transaction.removedOperationalData); - - val listeners = dataBroker.affectedListenersWithInitialState(affectedPaths); - - val transactionId = transaction.identifier; - - log.trace("Transaction: {} Started.",transactionId); - log.trace("Transaction: {} Affected Subtrees:",transactionId,affectedPaths); - // requesting commits - val Iterable> commitHandlers = dataBroker.affectedCommitHandlers(affectedPaths); - val List> handlerTransactions = new ArrayList(); - try { - for (handler : commitHandlers) { - handlerTransactions.add(handler.requestCommit(transaction)); - } - } catch (Exception e) { - log.error("Transaction: {} Request Commit failed", transactionId,e); - dataBroker.failedTransactionsCount.andIncrement - transaction.changeStatus(TransactionStatus.FAILED) - return rollback(handlerTransactions, e); - } - val List> results = new ArrayList(); - try { - for (subtransaction : handlerTransactions) { - results.add(subtransaction.finish()); - } - listeners.publishDataChangeEvent(); - } catch (Exception e) { - log.error("Transaction: {} Finish Commit failed",transactionId, e); - dataBroker.failedTransactionsCount.andIncrement - transaction.changeStatus(TransactionStatus.FAILED) - return rollback(handlerTransactions, e); - } - log.trace("Transaction: {} Finished successfully.",transactionId); - dataBroker.finishedTransactionsCount.andIncrement; - transaction.changeStatus(TransactionStatus.COMMITED) - return Rpcs.getRpcResult(true, TransactionStatus.COMMITED, Collections.emptySet()); - - } - - def void publishDataChangeEvent(ImmutableList> listeners) { - for (listenerSet : listeners) { - val updatedConfiguration = dataBroker.readConfigurationData(listenerSet.path); - val updatedOperational = dataBroker.readOperationalData(listenerSet.path); - - val changeEvent = new DataChangeEventImpl(transaction, listenerSet.initialConfigurationState, - listenerSet.initialOperationalState, updatedOperational, updatedConfiguration); - for (listener : listenerSet.listeners) { - try { - listener.instance.onDataChanged(changeEvent); - - } catch (Exception e) { - e.printStackTrace(); - } - } - } - } - - def rollback(List> transactions, Exception e) { - for (transaction : transactions) { - transaction.rollback() - } - - // FIXME return encountered error. - return Rpcs.getRpcResult(false, TransactionStatus.FAILED, Collections.emptySet()); - } -} - -public abstract class AbstractDataTransaction

, D> extends AbstractDataModification { - - private static val LOG = LoggerFactory.getLogger(AbstractDataTransaction); - - @Property - private val Object identifier; - - var TransactionStatus status; - - var AbstractDataBroker broker; - - protected new(Object identifier,AbstractDataBroker dataBroker) { - super(dataBroker); - _identifier = identifier; - broker = dataBroker; - status = TransactionStatus.NEW; - LOG.debug("Transaction {} Allocated.", identifier); - - //listeners = new ListenerRegistry<>(); - } - - override commit() { - return broker.commit(this); - } - - override readConfigurationData(P path) { - val local = this.updatedConfigurationData.get(path); - if(local != null) { - return local; - } - - return broker.readConfigurationData(path); - } - - override readOperationalData(P path) { - val local = this.updatedOperationalData.get(path); - if(local != null) { - return local; - } - return broker.readOperationalData(path); - } - - override hashCode() { - return identifier.hashCode; - } - - override equals(Object obj) { - if (this === obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - val other = (obj as AbstractDataTransaction); - if (broker == null) { - if (other.broker != null) - return false; - } else if (!broker.equals(other.broker)) - return false; - if (identifier == null) { - if (other.identifier != null) - return false; - } else if (!identifier.equals(other.identifier)) - return false; - return true; - } - - override TransactionStatus getStatus() { - return status; - } - - protected abstract def void onStatusChange(TransactionStatus status); - - public def changeStatus(TransactionStatus status) { - LOG.debug("Transaction {} transitioned from {} to {}", identifier, this.status, status); - this.status = status; - onStatusChange(status); - } - -} diff --git a/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/AbstractDataTransaction.java b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/AbstractDataTransaction.java new file mode 100644 index 0000000000..c73a627799 --- /dev/null +++ b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/AbstractDataTransaction.java @@ -0,0 +1,108 @@ +/** + * 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.sal.common.impl.service; + +import java.util.concurrent.Future; + +import org.opendaylight.controller.md.sal.common.api.TransactionStatus; +import org.opendaylight.controller.md.sal.common.impl.AbstractDataModification; +import org.opendaylight.yangtools.concepts.Path; +import org.opendaylight.yangtools.yang.common.RpcResult; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@SuppressWarnings("all") +public abstract class AbstractDataTransaction

, D extends Object> extends + AbstractDataModification { + private final static Logger LOG = LoggerFactory.getLogger(AbstractDataTransaction.class); + + private final Object identifier; + + @Override + public Object getIdentifier() { + return this.identifier; + } + + private TransactionStatus status; + + private final AbstractDataBroker broker; + + protected AbstractDataTransaction(final Object identifier, + final AbstractDataBroker dataBroker) { + super(dataBroker); + this.identifier = identifier; + this.broker = dataBroker; + this.status = TransactionStatus.NEW; + AbstractDataTransaction.LOG.debug("Transaction {} Allocated.", identifier); + } + + @Override + public Future> commit() { + return this.broker.commit(this); + } + + @Override + public D readConfigurationData(final P path) { + final D local = getUpdatedConfigurationData().get(path); + if (local != null) { + return local; + } + return this.broker.readConfigurationData(path); + } + + @Override + public D readOperationalData(final P path) { + final D local = this.getUpdatedOperationalData().get(path); + if (local != null) { + return local; + } + return this.broker.readOperationalData(path); + } + + + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((identifier == null) ? 0 : identifier.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + AbstractDataTransaction other = (AbstractDataTransaction) obj; + if (identifier == null) { + if (other.identifier != null) + return false; + } else if (!identifier.equals(other.identifier)) + return false; + return true; + } + + @Override + public TransactionStatus getStatus() { + return this.status; + } + + protected abstract void onStatusChange(final TransactionStatus status); + + public void changeStatus(final TransactionStatus status) { + Object _identifier = this.getIdentifier(); + AbstractDataTransaction.LOG + .debug("Transaction {} transitioned from {} to {}", _identifier, this.status, status); + this.status = status; + this.onStatusChange(status); + } +} diff --git a/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/DataChangeEventImpl.java b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/DataChangeEventImpl.java index 7f5e466c00..691c303688 100644 --- a/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/DataChangeEventImpl.java +++ b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/DataChangeEventImpl.java @@ -20,8 +20,6 @@ public class DataChangeEventImpl

, D> implements DataChangeEven private final DataChange dataChange; private final D originalConfigurationSubtree; - - private final D originalOperationalSubtree; private final D updatedOperationalSubtree; private final D updatedConfigurationSubtree; diff --git a/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/DataChangeListenerRegistration.java b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/DataChangeListenerRegistration.java new file mode 100644 index 0000000000..57d511ecf2 --- /dev/null +++ b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/DataChangeListenerRegistration.java @@ -0,0 +1,37 @@ +/** + * 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.sal.common.impl.service; + +import org.opendaylight.controller.md.sal.common.api.data.DataChangeListener; +import org.opendaylight.yangtools.concepts.AbstractObjectRegistration; +import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.opendaylight.yangtools.concepts.Path; + +@SuppressWarnings("all") +class DataChangeListenerRegistration

, D extends Object, DCL extends DataChangeListener> extends + AbstractObjectRegistration implements ListenerRegistration { + private AbstractDataBroker dataBroker; + + private final P path; + + public P getPath() { + return this.path; + } + + public DataChangeListenerRegistration(final P path, final DCL instance, final AbstractDataBroker broker) { + super(instance); + this.dataBroker = broker; + this.path = path; + } + + @Override + protected void removeRegistration() { + this.dataBroker.removeListener(this); + this.dataBroker = null; + } +} diff --git a/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/ImmutableDataChangeEvent.java b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/ImmutableDataChangeEvent.java new file mode 100644 index 0000000000..776ff7bfb2 --- /dev/null +++ b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/ImmutableDataChangeEvent.java @@ -0,0 +1,226 @@ +package org.opendaylight.controller.md.sal.common.impl.service; + +import java.util.Map; +import java.util.Set; + +import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent; +import org.opendaylight.controller.md.sal.common.api.data.DataModification; +import org.opendaylight.yangtools.concepts.Path; + +import com.google.common.base.Predicate; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Maps; + +final class ImmutableDataChangeEvent

, D> implements DataChangeEvent { + + private final D updatedOperationalSubtree; + private final Map updatedOperational; + private final D updatedConfigurationSubtree; + private final Map updatedConfiguration; + private final Set

removedOperational; + private final Set

removedConfiguration; + private final D originalOperationalSubtree; + private final Map originalOperational; + private final D originalConfigurationSubtree; + private final Map originalConfiguration; + private final Map createdOperational; + private final Map createdConfiguration; + + + public ImmutableDataChangeEvent(Builder builder) { + + createdConfiguration = builder.getCreatedConfiguration().build(); + createdOperational = builder.getCreatedOperational().build(); + originalConfiguration = builder.getOriginalConfiguration().build(); + originalConfigurationSubtree = builder.getOriginalConfigurationSubtree(); + originalOperational = builder.getOriginalOperational().build(); + originalOperationalSubtree = builder.getOriginalOperationalSubtree(); + removedConfiguration = builder.getRemovedConfiguration().build(); + removedOperational = builder.getRemovedOperational().build(); + updatedConfiguration = builder.getUpdatedConfiguration().build(); + updatedConfigurationSubtree = builder.getUpdatedConfigurationSubtree(); + updatedOperational = builder.getUpdatedOperational().build(); + updatedOperationalSubtree = builder.getUpdatedOperationalSubtree(); + } + + @Override + public Map getCreatedConfigurationData() { + return createdConfiguration; + } + + @Override + public Map getCreatedOperationalData() { + return createdOperational; + } + + @Override + public Map getOriginalConfigurationData() { + return originalConfiguration; + } + @Override + public D getOriginalConfigurationSubtree() { + return originalConfigurationSubtree; + } + @Override + public Map getOriginalOperationalData() { + return originalOperational; + } + @Override + public D getOriginalOperationalSubtree() { + return originalOperationalSubtree; + } + @Override + public Set

getRemovedConfigurationData() { + return removedConfiguration; + } + @Override + public Set

getRemovedOperationalData() { + return removedOperational; + } + @Override + public Map getUpdatedConfigurationData() { + return updatedConfiguration; + } + @Override + public D getUpdatedConfigurationSubtree() { + return updatedConfigurationSubtree; + } + @Override + public Map getUpdatedOperationalData() { + return updatedOperational; + } + @Override + public D getUpdatedOperationalSubtree() { + return updatedOperationalSubtree; + } + + static final

,D> Builder builder() { + return new Builder<>(); + } + + static final class Builder

,D> { + + private D updatedOperationalSubtree; + private D originalOperationalSubtree; + private D originalConfigurationSubtree; + private D updatedConfigurationSubtree; + + private final ImmutableMap.Builder updatedOperational = ImmutableMap.builder(); + private final ImmutableMap.Builder updatedConfiguration = ImmutableMap.builder(); + private final ImmutableSet.Builder

removedOperational = ImmutableSet.builder(); + private final ImmutableSet.Builder

removedConfiguration = ImmutableSet.builder(); + private final ImmutableMap.Builder originalOperational = ImmutableMap.builder(); + + private final ImmutableMap.Builder originalConfiguration = ImmutableMap.builder(); + private final ImmutableMap.Builder createdOperational = ImmutableMap.builder(); + private final ImmutableMap.Builder createdConfiguration = ImmutableMap.builder(); + + + protected Builder addTransaction(DataModification data, Predicate

keyFilter) { + updatedOperational.putAll(Maps.filterKeys(data.getUpdatedOperationalData(), keyFilter)); + updatedConfiguration.putAll(Maps.filterKeys(data.getUpdatedConfigurationData(), keyFilter)); + originalConfiguration.putAll(Maps.filterKeys(data.getOriginalConfigurationData(), keyFilter)); + originalOperational.putAll(Maps.filterKeys(data.getOriginalOperationalData(), keyFilter)); + createdOperational.putAll(Maps.filterKeys(data.getCreatedOperationalData(), keyFilter)); + createdConfiguration.putAll(Maps.filterKeys(data.getCreatedConfigurationData(), keyFilter)); + return this; + } + + protected Builder addConfigurationChangeSet(RootedChangeSet changeSet) { + if(changeSet == null) { + return this; + } + + originalConfiguration.putAll(changeSet.getOriginal()); + createdConfiguration.putAll(changeSet.getCreated()); + updatedConfiguration.putAll(changeSet.getUpdated()); + removedConfiguration.addAll(changeSet.getRemoved()); + return this; + } + + protected Builder addOperationalChangeSet(RootedChangeSet changeSet) { + if(changeSet == null) { + return this; + } + originalOperational.putAll(changeSet.getOriginal()); + createdOperational.putAll(changeSet.getCreated()); + updatedOperational.putAll(changeSet.getUpdated()); + removedOperational.addAll(changeSet.getRemoved()); + return this; + } + + protected ImmutableDataChangeEvent build() { + return new ImmutableDataChangeEvent(this); + } + + protected D getUpdatedOperationalSubtree() { + return updatedOperationalSubtree; + } + + protected Builder setUpdatedOperationalSubtree(D updatedOperationalSubtree) { + this.updatedOperationalSubtree = updatedOperationalSubtree; + return this; + } + + protected D getOriginalOperationalSubtree() { + return originalOperationalSubtree; + } + + protected Builder setOriginalOperationalSubtree(D originalOperationalSubtree) { + this.originalOperationalSubtree = originalOperationalSubtree; + return this; + } + + protected D getOriginalConfigurationSubtree() { + return originalConfigurationSubtree; + } + + protected Builder setOriginalConfigurationSubtree(D originalConfigurationSubtree) { + this.originalConfigurationSubtree = originalConfigurationSubtree; + return this; + } + + protected D getUpdatedConfigurationSubtree() { + return updatedConfigurationSubtree; + } + + protected Builder setUpdatedConfigurationSubtree(D updatedConfigurationSubtree) { + this.updatedConfigurationSubtree = updatedConfigurationSubtree; + return this; + } + + protected ImmutableMap.Builder getUpdatedOperational() { + return updatedOperational; + } + + protected ImmutableMap.Builder getUpdatedConfiguration() { + return updatedConfiguration; + } + + protected ImmutableSet.Builder

getRemovedOperational() { + return removedOperational; + } + + protected ImmutableSet.Builder

getRemovedConfiguration() { + return removedConfiguration; + } + + protected ImmutableMap.Builder getOriginalOperational() { + return originalOperational; + } + + protected ImmutableMap.Builder getOriginalConfiguration() { + return originalConfiguration; + } + + protected ImmutableMap.Builder getCreatedOperational() { + return createdOperational; + } + + protected ImmutableMap.Builder getCreatedConfiguration() { + return createdConfiguration; + } + } + +} diff --git a/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/ListenerStateCapture.java b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/ListenerStateCapture.java new file mode 100644 index 0000000000..502ca90ab9 --- /dev/null +++ b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/ListenerStateCapture.java @@ -0,0 +1,118 @@ +package org.opendaylight.controller.md.sal.common.impl.service; + +import java.util.Map; + +import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent; +import org.opendaylight.controller.md.sal.common.api.data.DataChangeListener; +import org.opendaylight.controller.md.sal.common.api.data.DataModification; +import org.opendaylight.yangtools.concepts.Path; + +import com.google.common.base.Predicate; + +public final class ListenerStateCapture

, D, DCL extends DataChangeListener> { + + final P path; + + final Iterable> listeners; + + D initialOperationalState; + + D initialConfigurationState; + + D finalConfigurationState; + + D finalOperationalState; + + Map additionalConfigOriginal; + Map additionalConfigCreated; + Map additionalConfigUpdated; + Map additionalConfigDeleted; + + Map additionalOperOriginal; + Map additionalOperCreated; + Map additionalOperUpdated; + Map additionalOperDeleted; + + RootedChangeSet normalizedConfigurationChanges; + RootedChangeSet normalizedOperationalChanges; + + private final Predicate

containsPredicate; + + public ListenerStateCapture(P path, Iterable> listeners, + Predicate

containsPredicate) { + super(); + this.path = path; + this.listeners = listeners; + this.containsPredicate = containsPredicate; + } + + protected D getInitialOperationalState() { + return initialOperationalState; + } + + protected void setInitialOperationalState(D initialOperationalState) { + this.initialOperationalState = initialOperationalState; + } + + protected D getInitialConfigurationState() { + return initialConfigurationState; + } + + protected void setInitialConfigurationState(D initialConfigurationState) { + this.initialConfigurationState = initialConfigurationState; + } + + protected P getPath() { + return path; + } + + protected Iterable> getListeners() { + return listeners; + } + + protected D getFinalConfigurationState() { + return finalConfigurationState; + } + + protected void setFinalConfigurationState(D finalConfigurationState) { + this.finalConfigurationState = finalConfigurationState; + } + + protected D getFinalOperationalState() { + return finalOperationalState; + } + + protected void setFinalOperationalState(D finalOperationalState) { + this.finalOperationalState = finalOperationalState; + } + + protected RootedChangeSet getNormalizedConfigurationChanges() { + return normalizedConfigurationChanges; + } + + protected void setNormalizedConfigurationChanges(RootedChangeSet normalizedConfigurationChanges) { + this.normalizedConfigurationChanges = normalizedConfigurationChanges; + } + + protected RootedChangeSet getNormalizedOperationalChanges() { + return normalizedOperationalChanges; + } + + protected void setNormalizedOperationalChanges(RootedChangeSet normalizedOperationalChange) { + this.normalizedOperationalChanges = normalizedOperationalChange; + } + + protected DataChangeEvent createEvent(DataModification modification) { + return ImmutableDataChangeEvent. builder()// + .addTransaction(modification, containsPredicate) // + .addConfigurationChangeSet(normalizedConfigurationChanges) // + .addOperationalChangeSet(normalizedOperationalChanges) // + .setOriginalConfigurationSubtree(initialConfigurationState) // + .setOriginalOperationalSubtree(initialOperationalState) // + .setUpdatedConfigurationSubtree(finalConfigurationState) // + .setUpdatedOperationalSubtree(finalOperationalState) // + .build(); + + } + +} diff --git a/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/RootedChangeSet.java b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/RootedChangeSet.java new file mode 100644 index 0000000000..e0525657e5 --- /dev/null +++ b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/RootedChangeSet.java @@ -0,0 +1,66 @@ +package org.opendaylight.controller.md.sal.common.impl.service; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import org.opendaylight.yangtools.concepts.Path; + +public class RootedChangeSet

,D> { + + private final P root; + private final Map original; + private final Map created = new HashMap<>(); + private final Map updated = new HashMap<>(); + private final Set

removed = new HashSet<>(); + + + + public RootedChangeSet(P root,Map original) { + super(); + this.root = root; + this.original = original; + } + + protected P getRoot() { + return root; + } + + protected Map getOriginal() { + return original; + } + + protected Map getCreated() { + return created; + } + + protected Map getUpdated() { + return updated; + } + + protected Set

getRemoved() { + return removed; + } + + public void addCreated(Map created) { + this.created.putAll(created); + } + + public void addCreated(Entry entry) { + created.put(entry.getKey(), entry.getValue()); + } + + public void addUpdated(Entry entry) { + updated.put(entry.getKey(), entry.getValue()); + } + + public void addRemoval(P path) { + removed.add(path); + } + + public boolean isChange() { + return !created.isEmpty() || !updated.isEmpty() || !removed.isEmpty(); + } +} diff --git a/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/TwoPhaseCommit.java b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/TwoPhaseCommit.java new file mode 100644 index 0000000000..e99fc0f24c --- /dev/null +++ b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/TwoPhaseCommit.java @@ -0,0 +1,237 @@ +/** + * 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.sal.common.impl.service; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; + +import org.opendaylight.controller.md.sal.common.api.TransactionStatus; +import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent; +import org.opendaylight.controller.md.sal.common.api.data.DataChangeListener; +import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler; +import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction; +import org.opendaylight.controller.sal.common.util.Rpcs; +import org.opendaylight.yangtools.concepts.Path; +import org.opendaylight.yangtools.yang.common.RpcError; +import org.opendaylight.yangtools.yang.common.RpcResult; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.Optional; +import com.google.common.base.Predicate; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableList.Builder; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Sets; + +public class TwoPhaseCommit

, D extends Object, DCL extends DataChangeListener> implements + Callable> { + private final static Logger log = LoggerFactory.getLogger(TwoPhaseCommit.class); + + private final AbstractDataTransaction transaction; + + private final AbstractDataBroker dataBroker; + + public TwoPhaseCommit(final AbstractDataTransaction transaction, final AbstractDataBroker broker) { + this.transaction = transaction; + this.dataBroker = broker; + } + + @Override + public RpcResult call() throws Exception { + final Object transactionId = this.transaction.getIdentifier(); + + Set

changedPaths = ImmutableSet.

builder().addAll(transaction.getUpdatedConfigurationData().keySet()) + .addAll(transaction.getCreatedConfigurationData().keySet()) + .addAll(transaction.getRemovedConfigurationData()) + .addAll(transaction.getUpdatedOperationalData().keySet()) + .addAll(transaction.getCreatedOperationalData().keySet()) + .addAll(transaction.getRemovedOperationalData()).build(); + + log.trace("Transaction: {} Affected Subtrees:", transactionId, changedPaths); + + final ImmutableList.Builder> listenersBuilder = ImmutableList.builder(); + listenersBuilder.addAll(dataBroker.affectedListeners(changedPaths)); + filterProbablyAffectedListeners(dataBroker.probablyAffectedListeners(changedPaths),listenersBuilder); + + + + final ImmutableList> listeners = listenersBuilder.build(); + final Iterable> commitHandlers = dataBroker.affectedCommitHandlers(changedPaths); + captureInitialState(listeners); + + + log.trace("Transaction: {} Starting Request Commit.",transactionId); + final List> handlerTransactions = new ArrayList<>(); + try { + for (final DataCommitHandler handler : commitHandlers) { + DataCommitTransaction requestCommit = handler.requestCommit(this.transaction); + if (requestCommit != null) { + handlerTransactions.add(requestCommit); + } else { + log.debug("Transaction: {}, Handler {} is not participating in transaction.", transactionId, + handler); + } + } + } catch (Exception e) { + log.error("Transaction: {} Request Commit failed", transactionId, e); + dataBroker.getFailedTransactionsCount().getAndIncrement(); + this.transaction.changeStatus(TransactionStatus.FAILED); + return this.rollback(handlerTransactions, e); + + } + + log.trace("Transaction: {} Starting Finish.",transactionId); + final List> results = new ArrayList>(); + try { + for (final DataCommitTransaction subtransaction : handlerTransactions) { + results.add(subtransaction.finish()); + } + } catch (Exception e) { + log.error("Transaction: {} Finish Commit failed", transactionId, e); + dataBroker.getFailedTransactionsCount().getAndIncrement(); + transaction.changeStatus(TransactionStatus.FAILED); + return this.rollback(handlerTransactions, e); + } + + + dataBroker.getFinishedTransactionsCount().getAndIncrement(); + transaction.changeStatus(TransactionStatus.COMMITED); + + log.trace("Transaction: {} Finished successfully.", transactionId); + + captureFinalState(listeners); + + log.trace("Transaction: {} Notifying listeners."); + + publishDataChangeEvent(listeners); + return Rpcs. getRpcResult(true, TransactionStatus.COMMITED, + Collections. emptySet()); + } + + private void captureInitialState(ImmutableList> listeners) { + for (ListenerStateCapture state : listeners) { + state.setInitialConfigurationState(dataBroker.readConfigurationData(state.getPath())); + state.setInitialOperationalState(dataBroker.readOperationalData(state.getPath())); + } + } + + + private void captureFinalState(ImmutableList> listeners) { + for (ListenerStateCapture state : listeners) { + state.setFinalConfigurationState(dataBroker.readConfigurationData(state.getPath())); + state.setFinalOperationalState(dataBroker.readOperationalData(state.getPath())); + } + } + + private void filterProbablyAffectedListeners( + ImmutableList> probablyAffectedListeners, Builder> reallyAffected) { + + for(ListenerStateCapture listenerSet : probablyAffectedListeners) { + P affectedPath = listenerSet.getPath(); + Optional> configChange = resolveConfigChange(affectedPath); + Optional> operChange = resolveOperChange(affectedPath); + + if(configChange.isPresent() || operChange.isPresent()) { + reallyAffected.add(listenerSet); + if(configChange.isPresent()) { + listenerSet.setNormalizedConfigurationChanges(configChange.get()); + } + + if(operChange.isPresent()) { + listenerSet.setNormalizedOperationalChanges(operChange.get()); + } + } + } + } + + private Optional> resolveOperChange(P affectedPath) { + Map originalOper = dataBroker.deepGetBySubpath(transaction.getOriginalOperationalData(),affectedPath); + Map createdOper = dataBroker.deepGetBySubpath(transaction.getCreatedOperationalData(),affectedPath); + Map updatedOper = dataBroker.deepGetBySubpath(transaction.getUpdatedOperationalData(),affectedPath); + Set

removedOper = Sets.filter(transaction.getRemovedOperationalData(), dataBroker.createIsContainedPredicate(affectedPath)); + return resolveChanges(affectedPath,originalOper,createdOper,updatedOper,removedOper); + } + + private Optional> resolveConfigChange(P affectedPath) { + Map originalConfig = dataBroker.deepGetBySubpath(transaction.getOriginalConfigurationData(),affectedPath); + Map createdConfig = dataBroker.deepGetBySubpath(transaction.getCreatedConfigurationData(),affectedPath); + Map updatedConfig = dataBroker.deepGetBySubpath(transaction.getUpdatedConfigurationData(),affectedPath); + Set

removedConfig = Sets.filter(transaction.getRemovedConfigurationData(), dataBroker.createIsContainedPredicate(affectedPath)); + return resolveChanges(affectedPath,originalConfig,createdConfig,updatedConfig,removedConfig); + } + + private Optional> resolveChanges(P affectedPath, Map originalConfig, Map createdConfig, Map updatedConfig,Set

potentialDeletions) { + Predicate

isContained = dataBroker.createIsContainedPredicate(affectedPath); + + if(createdConfig.isEmpty() && updatedConfig.isEmpty() && potentialDeletions.isEmpty()) { + return Optional.absent(); + } + RootedChangeSet changeSet = new RootedChangeSet(affectedPath,originalConfig); + changeSet.addCreated(createdConfig); + + for(Entry entry : updatedConfig.entrySet()) { + if(originalConfig.containsKey(entry.getKey())) { + changeSet.addUpdated(entry); + } else { + changeSet.addCreated(entry); + } + } + + for(Entry entry : originalConfig.entrySet()) { + for(P deletion : potentialDeletions) { + if(isContained.apply(deletion)) { + changeSet.addRemoval(entry.getKey()); + } + } + } + + if(changeSet.isChange()) { + return Optional.of(changeSet); + } else { + return Optional.absent(); + } + + } + + public void publishDataChangeEvent(final ImmutableList> listeners) { + ExecutorService executor = this.dataBroker.getExecutor(); + final Runnable notifyTask = new Runnable() { + @Override + public void run() { + for (final ListenerStateCapture listenerSet : listeners) { + { + DataChangeEvent changeEvent = listenerSet.createEvent(transaction); + for (final DataChangeListenerRegistration listener : listenerSet.getListeners()) { + try { + listener.getInstance().onDataChanged(changeEvent); + } catch (Exception e) { + log.error("Unhandled exception when invoking listener {}", listener); + } + } + } + } + } + }; + executor.submit(notifyTask); + } + + public RpcResult rollback(final List> transactions, final Exception e) { + for (final DataCommitTransaction transaction : transactions) { + transaction.rollback(); + } + Set _emptySet = Collections. emptySet(); + return Rpcs. getRpcResult(false, TransactionStatus.FAILED, _emptySet); + } +} diff --git a/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/util/AbstractLockableDelegator.java b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/util/AbstractLockableDelegator.java index bd9748d3c5..4d756f1d67 100644 --- a/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/util/AbstractLockableDelegator.java +++ b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/util/AbstractLockableDelegator.java @@ -8,8 +8,6 @@ package org.opendaylight.controller.md.sal.common.impl.util; import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReadWriteLock; -import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock; import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock; @@ -23,8 +21,8 @@ public class AbstractLockableDelegator implements Delegator { private final ReentrantReadWriteLock delegateLock = new ReentrantReadWriteLock(); private final ReadLock delegateReadLock = delegateLock.readLock(); private final WriteLock delegateWriteLock = delegateLock.writeLock(); - - + + protected Lock getDelegateReadLock() { return delegateReadLock; } @@ -60,7 +58,7 @@ public class AbstractLockableDelegator implements Delegator { } /** - * + * * @param newDelegate * @return oldDelegate */ @@ -75,8 +73,8 @@ public class AbstractLockableDelegator implements Delegator { delegateWriteLock.unlock(); } } - - + + protected void onDelegateChanged(T oldDelegate, T newDelegate) { // NOOP in abstract calss; } diff --git a/opendaylight/md-sal/sal-common-util/src/main/java/org/opendaylight/controller/sal/common/util/Rpcs.java b/opendaylight/md-sal/sal-common-util/src/main/java/org/opendaylight/controller/sal/common/util/Rpcs.java index 356ec8ff7c..f303941871 100644 --- a/opendaylight/md-sal/sal-common-util/src/main/java/org/opendaylight/controller/sal/common/util/Rpcs.java +++ b/opendaylight/md-sal/sal-common-util/src/main/java/org/opendaylight/controller/sal/common/util/Rpcs.java @@ -8,9 +8,7 @@ package org.opendaylight.controller.sal.common.util; import java.io.Serializable; -import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; import org.opendaylight.yangtools.concepts.Immutable; import org.opendaylight.yangtools.yang.common.RpcError; @@ -19,12 +17,12 @@ import org.opendaylight.yangtools.yang.common.RpcResult; import com.google.common.collect.ImmutableList; public class Rpcs { - + public static RpcResult getRpcResult(boolean successful) { RpcResult ret = new RpcResultTO(successful, null, ImmutableList.of()); return ret; } - + public static RpcResult getRpcResult(boolean successful, T result, Collection errors) { RpcResult ret = new RpcResultTO(successful, result, errors); @@ -34,9 +32,9 @@ public class Rpcs { public static RpcResult getRpcResult(boolean successful, Collection errors) { return new RpcResultTO(successful, null, errors); } - - private static class RpcResultTO implements RpcResult, Serializable, Immutable { + private static class RpcResultTO implements RpcResult, Serializable, Immutable { + private static final long serialVersionUID = 1L; private final Collection errors; private final T result; private final boolean successful; diff --git a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/AbstractProvider.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/AbstractProvider.java index 1cb1a2bc85..22b0bf25cf 100644 --- a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/AbstractProvider.java +++ b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/AbstractProvider.java @@ -10,9 +10,6 @@ package org.opendaylight.controller.sal.core.api; import java.util.Collection; import java.util.Collections; -import javax.naming.Context; - -import org.opendaylight.controller.sal.core.api.Broker.ProviderSession; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceReference; @@ -59,18 +56,18 @@ public abstract class AbstractProvider implements BundleActivator, Provider,Serv broker.registerProvider(this, context); return broker; } - + return null; } - + @Override public void modifiedService(ServiceReference reference, Broker service) { // NOOP } - + @Override public void removedService(ServiceReference reference, Broker service) { stopImpl(context); } - + } diff --git a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/RpcProvisionRegistry.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/RpcProvisionRegistry.java index 24cb99f8c3..8a9d167865 100644 --- a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/RpcProvisionRegistry.java +++ b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/RpcProvisionRegistry.java @@ -14,7 +14,7 @@ import org.opendaylight.yangtools.concepts.ListenerRegistration; import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier; -public interface RpcProvisionRegistry extends BrokerService, RouteChangePublisher { +public interface RpcProvisionRegistry extends RpcImplementation, BrokerService, RouteChangePublisher { /** * Registers an implementation of the rpc. diff --git a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/data/DataModificationTransaction.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/data/DataModificationTransaction.java index 774de271af..9706bbacdb 100644 --- a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/data/DataModificationTransaction.java +++ b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/data/DataModificationTransaction.java @@ -8,8 +8,6 @@ package org.opendaylight.controller.sal.core.api.data; import java.util.EventListener; -import java.util.Map; -import java.util.Set; import java.util.concurrent.Future; import org.opendaylight.controller.md.sal.common.api.TransactionStatus; @@ -23,31 +21,28 @@ public interface DataModificationTransaction extends DataModification> commit(); - + ListenerRegistration registerListener(DataTransactionListener listener); - - + public interface DataTransactionListener extends EventListener { - void onStatusUpdated(DataModificationTransaction transaction,TransactionStatus status); - } - - - } diff --git a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/mount/MountProvisionInstance.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/mount/MountProvisionInstance.java index 299fe1b558..29e3b911c1 100644 --- a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/mount/MountProvisionInstance.java +++ b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/mount/MountProvisionInstance.java @@ -10,7 +10,6 @@ package org.opendaylight.controller.sal.core.api.mount; import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry; import org.opendaylight.controller.sal.core.api.data.DataProviderService; import org.opendaylight.controller.sal.core.api.notify.NotificationPublishService; -import com.google.common.base.Optional; import org.opendaylight.yangtools.yang.model.api.SchemaContext; public interface MountProvisionInstance extends // diff --git a/opendaylight/md-sal/sal-dom-broker/pom.xml b/opendaylight/md-sal/sal-dom-broker/pom.xml index 8b193e03aa..8553d9eea5 100644 --- a/opendaylight/md-sal/sal-dom-broker/pom.xml +++ b/opendaylight/md-sal/sal-dom-broker/pom.xml @@ -64,6 +64,7 @@ + org.opendaylight.yangtools yang-maven-plugin diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BrokerImpl.xtend b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BrokerImpl.xtend index aa5138a04d..8f734d7d4c 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BrokerImpl.xtend +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BrokerImpl.xtend @@ -73,7 +73,7 @@ public class BrokerImpl implements Broker, RpcProvisionRegistry, AutoCloseable { return session; } - protected def Future> invokeRpc(QName rpc, CompositeNode input) { + protected def Future> invokeRpcAsync(QName rpc, CompositeNode input) { val result = executor.submit([|router.invokeRpc(rpc, input)] as Callable>); return result; } @@ -135,5 +135,13 @@ public class BrokerImpl implements Broker, RpcProvisionRegistry, AutoCloseable { override > registerRouteChangeListener(L listener) { return router.registerRouteChangeListener(listener); } + + override invokeRpc(QName rpc,CompositeNode input){ + return router.invokeRpc(rpc,input) + } + + override getSupportedRpcs() { + return router.getSupportedRpcs(); + } } diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/ConsumerContextImpl.xtend b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/ConsumerContextImpl.xtend index e4808e9bd6..813f52b67d 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/ConsumerContextImpl.xtend +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/ConsumerContextImpl.xtend @@ -37,7 +37,7 @@ class ConsumerContextImpl implements ConsumerSession { } override rpc(QName rpc, CompositeNode input) { - return broker.invokeRpc(rpc, input); + return broker.invokeRpcAsync(rpc, input); } override T getService(Class service) { diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/MountPointImpl.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/MountPointImpl.java index 5a3e060a3c..a8bdddb510 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/MountPointImpl.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/MountPointImpl.java @@ -219,4 +219,6 @@ public class MountPointImpl implements MountProvisionInstance, SchemaContextProv L listener) { return rpcs.registerRouteChangeListener(listener); } + + } diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/NotificationModule.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/NotificationModule.java index 403f7c8da0..bbe017f009 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/NotificationModule.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/NotificationModule.java @@ -9,14 +9,13 @@ package org.opendaylight.controller.sal.dom.broker; import java.util.Collection; import java.util.Collections; -import java.util.HashSet; import java.util.Map; import java.util.Map.Entry; import java.util.Set; -import org.opendaylight.controller.sal.core.api.BrokerService; import org.opendaylight.controller.sal.core.api.Broker.ConsumerSession; import org.opendaylight.controller.sal.core.api.Broker.ProviderSession; +import org.opendaylight.controller.sal.core.api.BrokerService; import org.opendaylight.controller.sal.core.api.Consumer.ConsumerFunctionality; import org.opendaylight.controller.sal.core.api.Provider.ProviderFunctionality; import org.opendaylight.controller.sal.core.api.notify.NotificationListener; @@ -37,7 +36,7 @@ public class NotificationModule implements BrokerModule { private static Logger log = LoggerFactory .getLogger(NotificationModule.class); - private Multimap listeners = HashMultimap + private final Multimap listeners = HashMultimap .create(); private static final Set> PROVIDED_SERVICE_TYPE = ImmutableSet @@ -114,11 +113,12 @@ public class NotificationModule implements BrokerModule { private class NotificationConsumerSessionImpl implements NotificationService { - private Multimap consumerListeners = HashMultimap + private final Multimap consumerListeners = HashMultimap .create(); private boolean closed = false; + @Override public Registration addNotificationListener(QName notification, NotificationListener listener) { checkSessionState(); diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/NotificationRouterImpl.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/NotificationRouterImpl.java index 0b184fc86e..50af3fbfc1 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/NotificationRouterImpl.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/NotificationRouterImpl.java @@ -8,21 +8,8 @@ package org.opendaylight.controller.sal.dom.broker.impl; import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; -import org.opendaylight.controller.sal.core.api.BrokerService; -import org.opendaylight.controller.sal.core.api.Broker.ConsumerSession; -import org.opendaylight.controller.sal.core.api.Broker.ProviderSession; -import org.opendaylight.controller.sal.core.api.Consumer.ConsumerFunctionality; -import org.opendaylight.controller.sal.core.api.Provider.ProviderFunctionality; import org.opendaylight.controller.sal.core.api.notify.NotificationListener; -import org.opendaylight.controller.sal.core.api.notify.NotificationPublishService; -import org.opendaylight.controller.sal.core.api.notify.NotificationService; -import org.opendaylight.controller.sal.core.spi.BrokerModule; import org.opendaylight.controller.sal.dom.broker.spi.NotificationRouter; import org.opendaylight.yangtools.concepts.AbstractObjectRegistration; import org.opendaylight.yangtools.concepts.Registration; @@ -32,16 +19,15 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.collect.HashMultimap; -import com.google.common.collect.ImmutableSet; import com.google.common.collect.Multimap; import com.google.common.collect.Multimaps; public class NotificationRouterImpl implements NotificationRouter { private static Logger log = LoggerFactory.getLogger(NotificationRouterImpl.class); - private Multimap> listeners = Multimaps.synchronizedSetMultimap(HashMultimap.>create()); + private final Multimap> listeners = Multimaps.synchronizedSetMultimap(HashMultimap.>create()); // private Registration defaultListener; - + private void sendNotification(CompositeNode notification) { final QName type = notification.getNodeType(); final Collection> toNotify = listeners.get(type); @@ -66,7 +52,7 @@ public class NotificationRouterImpl implements NotificationRouter { public void publish(CompositeNode notification) { sendNotification(notification); } - + @Override public Registration addNotificationListener(QName notification, NotificationListener listener) { ListenerRegistration ret = new ListenerRegistration(notification, listener); diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/SchemaAwareDataStoreAdapter.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/SchemaAwareDataStoreAdapter.java index 3e6a8252b7..b02a37c300 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/SchemaAwareDataStoreAdapter.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/SchemaAwareDataStoreAdapter.java @@ -7,6 +7,8 @@ */ package org.opendaylight.controller.sal.dom.broker.impl; +import static com.google.common.base.Preconditions.checkState; + import java.util.ArrayList; import java.util.Comparator; import java.util.Map.Entry; @@ -18,8 +20,8 @@ import org.opendaylight.controller.md.sal.common.api.data.DataReader; import org.opendaylight.controller.md.sal.common.impl.AbstractDataModification; import org.opendaylight.controller.md.sal.common.impl.util.AbstractLockableDelegator; import org.opendaylight.controller.sal.core.api.data.DataStore; +import org.opendaylight.controller.sal.dom.broker.util.YangDataOperations; import org.opendaylight.controller.sal.dom.broker.util.YangSchemaUtils; -import org.opendaylight.yangtools.yang.model.api.SchemaServiceListener; import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.common.RpcResult; import org.opendaylight.yangtools.yang.data.api.CompositeNode; @@ -28,25 +30,26 @@ import org.opendaylight.yangtools.yang.data.api.Node; import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl; import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; import org.opendaylight.yangtools.yang.model.api.SchemaContext; -import org.opendaylight.controller.sal.dom.broker.util.YangDataOperations; +import org.opendaylight.yangtools.yang.model.api.SchemaContextListener; +import org.opendaylight.yangtools.yang.model.api.SchemaServiceListener; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.base.Predicate; import com.google.common.collect.FluentIterable; - -import static com.google.common.base.Preconditions.*; +import com.google.common.collect.ImmutableSet; public class SchemaAwareDataStoreAdapter extends AbstractLockableDelegator implements // DataStore, // SchemaServiceListener, // + SchemaContextListener, // AutoCloseable { private final static Logger LOG = LoggerFactory.getLogger(SchemaAwareDataStoreAdapter.class); private SchemaContext schema = null; private boolean validationEnabled = false; - private DataReader reader = new MergeFirstLevelReader(); + private final DataReader reader = new MergeFirstLevelReader(); @Override public boolean containsConfigurationPath(InstanceIdentifier path) { @@ -164,7 +167,6 @@ public class SchemaAwareDataStoreAdapter extends AbstractLockableDelegator original) { - // NOOP for now NormalizedDataModification normalized = new NormalizedDataModification(original); for (Entry entry : original.getUpdatedConfigurationData().entrySet()) { normalized.putConfigurationData(entry.getKey(), entry.getValue()); @@ -173,14 +175,40 @@ public class SchemaAwareDataStoreAdapter extends AbstractLockableDelegator getConfigurationSubpaths(InstanceIdentifier entry) { + // FIXME: This should be replaced by index + Iterable paths = getStoredConfigurationPaths(); + + return getChildrenPaths(entry, paths); + + } + + public Iterable getOperationalSubpaths(InstanceIdentifier entry) { + // FIXME: This should be indexed + Iterable paths = getStoredOperationalPaths(); + + return getChildrenPaths(entry, paths); + } + + private static final Iterable getChildrenPaths(InstanceIdentifier entry, + Iterable paths) { + ImmutableSet.Builder children = ImmutableSet.builder(); + for (InstanceIdentifier potential : paths) { + if (entry.contains(potential)) { + children.add(entry); + } + } + return children.build(); + } + private final Comparator> preparationComparator = new Comparator>() { @Override public int compare(Entry o1, Entry o2) { @@ -282,7 +310,7 @@ public class SchemaAwareDataStoreAdapter extends AbstractLockableDelegator { - private Object identifier; + private final Object identifier; private TransactionStatus status; public NormalizedDataModification(DataModification original) { @@ -291,6 +319,29 @@ public class SchemaAwareDataStoreAdapter extends AbstractLockableDelegator paths = getOperationalSubpaths(entry); + removeOperationalData(entry); + for (InstanceIdentifier potential : paths) { + removeOperationalData(potential); + } + } + + public void deepRemoveConfigurationData(InstanceIdentifier entry) { + Iterable paths = getConfigurationSubpaths(entry); + removeConfigurationData(entry); + for (InstanceIdentifier potential : paths) { + removeConfigurationData(potential); + } + } + @Override public Object getIdentifier() { return this.identifier; diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/osgi/MountProviderServiceProxy.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/osgi/MountProviderServiceProxy.java index 0e63126bb3..24d5430d6d 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/osgi/MountProviderServiceProxy.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/osgi/MountProviderServiceProxy.java @@ -7,7 +7,6 @@ */ package org.opendaylight.controller.sal.dom.broker.osgi; -import org.opendaylight.controller.sal.core.api.data.DataBrokerService; import org.opendaylight.controller.sal.core.api.mount.MountProvisionInstance; import org.opendaylight.controller.sal.core.api.mount.MountProvisionService; import org.opendaylight.yangtools.concepts.ListenerRegistration; @@ -16,23 +15,26 @@ import org.osgi.framework.ServiceReference; public class MountProviderServiceProxy extends AbstractBrokerServiceProxy implements MountProvisionService{ - + public MountProviderServiceProxy(ServiceReference ref, MountProvisionService delegate) { super(ref, delegate); } + @Override public MountProvisionInstance getMountPoint(InstanceIdentifier path) { return getDelegate().getMountPoint(path); } + @Override public MountProvisionInstance createMountPoint(InstanceIdentifier path) { return getDelegate().createMountPoint(path); } + @Override public MountProvisionInstance createOrGetMountPoint(InstanceIdentifier path) { return getDelegate().createOrGetMountPoint(path); } - + @Override public ListenerRegistration registerProvisionListener(MountProvisionListener listener) { return getDelegate().registerProvisionListener(listener); diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/osgi/RpcProvisionRegistryProxy.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/osgi/RpcProvisionRegistryProxy.java index e375e14cf2..e218a95782 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/osgi/RpcProvisionRegistryProxy.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/osgi/RpcProvisionRegistryProxy.java @@ -16,9 +16,13 @@ import org.opendaylight.controller.sal.core.api.RpcRegistrationListener; 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 implements RpcProvisionRegistry { @@ -45,4 +49,15 @@ public class RpcProvisionRegistryProxy extends AbstractBrokerServiceProxy> ListenerRegistration registerRouteChangeListener(L listener) { return getDelegate().registerRouteChangeListener(listener); } + + + @Override + public Set getSupportedRpcs() { + return getDelegate().getSupportedRpcs(); + } + + @Override + public RpcResult invokeRpc(QName rpc, CompositeNode input) { + return getDelegate().invokeRpc(rpc,input); + } } diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/spi/RpcRouter.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/spi/RpcRouter.java index 9881be0481..d1523a01d6 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/spi/RpcRouter.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/spi/RpcRouter.java @@ -9,12 +9,10 @@ package org.opendaylight.controller.sal.dom.broker.spi; import java.util.Set; -import org.opendaylight.controller.sal.core.api.RpcImplementation; -import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry; import org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration; import org.opendaylight.controller.sal.core.api.Broker.RpcRegistration; -import org.opendaylight.controller.sal.core.api.RpcRegistrationListener; -import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.opendaylight.controller.sal.core.api.RpcImplementation; +import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry; import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.common.RpcResult; import org.opendaylight.yangtools.yang.data.api.CompositeNode; @@ -23,14 +21,14 @@ public interface RpcRouter extends RpcProvisionRegistry, RpcImplementation { @Override public RoutedRpcRegistration addRoutedRpcImplementation(QName rpcType, RpcImplementation implementation); - + @Override public RpcRegistration addRpcImplementation(QName rpcType, RpcImplementation implementation) throws IllegalArgumentException; - + @Override public Set getSupportedRpcs(); - + @Override public RpcResult invokeRpc(QName rpc, CompositeNode input); } diff --git a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/config/yang/md/sal/connector/netconf/NetconfConnectorModule.java b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/config/yang/md/sal/connector/netconf/NetconfConnectorModule.java index a04baaa912..ddaf6ea6c3 100644 --- a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/config/yang/md/sal/connector/netconf/NetconfConnectorModule.java +++ b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/config/yang/md/sal/connector/netconf/NetconfConnectorModule.java @@ -7,9 +7,18 @@ */ package org.opendaylight.controller.config.yang.md.sal.connector.netconf; -import com.google.common.net.InetAddresses; +import static org.opendaylight.controller.config.api.JmxAttributeValidationException.checkCondition; +import static org.opendaylight.controller.config.api.JmxAttributeValidationException.checkNotNull; import io.netty.channel.EventLoopGroup; import io.netty.util.concurrent.GlobalEventExecutor; + +import java.io.File; +import java.io.InputStream; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + import org.opendaylight.controller.netconf.client.NetconfClientDispatcher; import org.opendaylight.controller.netconf.client.NetconfSshClientDispatcher; import org.opendaylight.controller.netconf.util.handler.ssh.authentication.AuthenticationHandler; @@ -25,19 +34,11 @@ import org.osgi.framework.BundleContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.File; -import java.io.InputStream; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; - -import static org.opendaylight.controller.config.api.JmxAttributeValidationException.checkCondition; -import static org.opendaylight.controller.config.api.JmxAttributeValidationException.checkNotNull; +import com.google.common.net.InetAddresses; /** -* -*/ + * + */ public final class NetconfConnectorModule extends org.opendaylight.controller.config.yang.md.sal.connector.netconf.AbstractNetconfConnectorModule { private static final Logger logger = LoggerFactory.getLogger(NetconfConnectorModule.class); @@ -72,7 +73,7 @@ public final class NetconfConnectorModule extends org.opendaylight.controller.co @Override public java.lang.AutoCloseable createInstance() { - + getDomRegistryDependency(); NetconfDevice device = new NetconfDevice(getIdentifier().getInstanceName()); String addressValue = getAddress(); @@ -92,27 +93,27 @@ public final class NetconfConnectorModule extends org.opendaylight.controller.co } else { addressValue = getAddress().getIpv6Address().getValue(); } - */ + */ double sleepFactor = 1.0; int minSleep = 1000; Long maxSleep = null; Long deadline = null; ReconnectStrategy strategy = new TimedReconnectStrategy(GlobalEventExecutor.INSTANCE, getBetweenAttemptsTimeoutMillis(), minSleep, sleepFactor, maxSleep, connectionAttempts, deadline); - + device.setReconnectStrategy(strategy); - + InetAddress addr = InetAddresses.forString(addressValue); InetSocketAddress socketAddress = new InetSocketAddress(addr , getPort().intValue()); - + device.setProcessingExecutor(getGlobalProcessingExecutor()); - + device.setSocketAddress(socketAddress); device.setEventExecutor(getEventExecutorDependency()); device.setDispatcher(createDispatcher(clientConnectionTimeoutMillis)); device.setSchemaSourceProvider(getGlobalNetconfSchemaProvider(bundleContext)); - + getDomRegistryDependency().registerProvider(device, bundleContext); device.start(); return device; @@ -120,9 +121,9 @@ public final class NetconfConnectorModule extends org.opendaylight.controller.co private ExecutorService getGlobalProcessingExecutor() { if(GLOBAL_PROCESSING_EXECUTOR == null) { - + GLOBAL_PROCESSING_EXECUTOR = Executors.newCachedThreadPool(); - + } return GLOBAL_PROCESSING_EXECUTOR; } @@ -130,8 +131,8 @@ public final class NetconfConnectorModule extends org.opendaylight.controller.co private synchronized AbstractCachingSchemaSourceProvider getGlobalNetconfSchemaProvider(BundleContext bundleContext) { if(GLOBAL_NETCONF_SOURCE_PROVIDER == null) { String storageFile = "cache/schema"; -// File directory = bundleContext.getDataFile(storageFile); - File directory = new File("cache/schema"); + // File directory = bundleContext.getDataFile(storageFile); + File directory = new File(storageFile); SchemaSourceProvider defaultProvider = SchemaSourceProviders.noopProvider(); GLOBAL_NETCONF_SOURCE_PROVIDER = FilesystemSchemaCachingProvider.createFromStringSourceProvider(defaultProvider, directory); } diff --git a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/NetconfDevice.xtend b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/NetconfDevice.xtend index 7e88ea17d0..c9fb1fc0b8 100644 --- a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/NetconfDevice.xtend +++ b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/NetconfDevice.xtend @@ -125,7 +125,7 @@ AutoCloseable { checkState(schemaSourceProvider != null, "Schema Source Provider must be set.") checkState(eventExecutor != null, "Event executor must be set."); - val listener = new NetconfDeviceListener(this, eventExecutor); + val listener = new NetconfDeviceListener(this); val task = startClientTask(dispatcher, listener) if (mountInstance != null) { commitHandlerReg = mountInstance.registerCommitHandler(ROOT_PATH, this) diff --git a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/NetconfDeviceListener.java b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/NetconfDeviceListener.java index 69fe4aa190..13cd5dbcf0 100644 --- a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/NetconfDeviceListener.java +++ b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/NetconfDeviceListener.java @@ -7,61 +7,19 @@ */ package org.opendaylight.controller.sal.connect.netconf; -import com.google.common.base.Objects; - -import io.netty.util.concurrent.EventExecutor; -import io.netty.util.concurrent.Promise; - -import java.util.List; -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.locks.ReentrantLock; - -import org.eclipse.xtext.xbase.lib.Exceptions; -import org.eclipse.xtext.xbase.lib.Functions.Function0; import org.opendaylight.controller.netconf.api.NetconfMessage; +import org.opendaylight.controller.netconf.client.AbstractNetconfClientNotifySessionListener; import org.opendaylight.controller.netconf.client.NetconfClientSession; -import org.opendaylight.controller.netconf.client.NetconfClientSessionListener; -import org.opendaylight.controller.netconf.util.xml.XmlElement; -import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants; -import org.opendaylight.controller.sal.connect.netconf.NetconfDevice; -import org.opendaylight.controller.sal.connect.netconf.NetconfMapping; import org.opendaylight.controller.sal.core.api.mount.MountProvisionInstance; import org.opendaylight.yangtools.yang.data.api.CompositeNode; -import org.opendaylight.yangtools.yang.data.api.Node; -import org.w3c.dom.Document; - -@SuppressWarnings("all") -class NetconfDeviceListener extends NetconfClientSessionListener { - private final NetconfDevice device; - private final EventExecutor eventExecutor; - - public NetconfDeviceListener(final NetconfDevice device, final EventExecutor eventExecutor) { - this.device = device; - this.eventExecutor = eventExecutor; - } - private Promise messagePromise; - private ConcurrentMap> promisedMessages; +import com.google.common.base.Preconditions; - private final ReentrantLock promiseLock = new ReentrantLock(); +class NetconfDeviceListener extends AbstractNetconfClientNotifySessionListener { + private final NetconfDevice device; - public void onMessage(final NetconfClientSession session, final NetconfMessage message) { - if (isNotification(message)) { - this.onNotification(session, message); - } else { - try { - this.promiseLock.lock(); - boolean _notEquals = (!Objects.equal(this.messagePromise, null)); - if (_notEquals) { - this.device.logger.debug("Setting promised reply {} with message {}", this.messagePromise, message); - this.messagePromise.setSuccess(message); - this.messagePromise = null; - } - } finally { - this.promiseLock.unlock(); - } - } + public NetconfDeviceListener(final NetconfDevice device) { + this.device = Preconditions.checkNotNull(device); } /** @@ -76,6 +34,7 @@ class NetconfDeviceListener extends NetconfClientSessionListener { * NetconfClientSessionListener#onMessage(NetconfClientSession, * NetconfMessage)} */ + @Override public void onNotification(final NetconfClientSession session, final NetconfMessage message) { this.device.logger.debug("Received NETCONF notification.", message); CompositeNode domNotification = null; @@ -92,65 +51,4 @@ class NetconfDeviceListener extends NetconfClientSessionListener { } } } - - private static CompositeNode getNotificationBody(final CompositeNode node) { - List> _children = node.getChildren(); - for (final Node child : _children) { - if ((child instanceof CompositeNode)) { - return ((CompositeNode) child); - } - } - return null; - } - - public NetconfMessage getLastMessage(final int attempts, final int attemptMsDelay) throws InterruptedException { - final Promise promise = this.promiseReply(); - this.device.logger.debug("Waiting for reply {}", promise); - int _plus = (attempts * attemptMsDelay); - final boolean messageAvailable = promise.await(_plus); - if (messageAvailable) { - try { - try { - return promise.get(); - } catch (Throwable _e) { - throw Exceptions.sneakyThrow(_e); - } - } catch (final Throwable _t) { - if (_t instanceof ExecutionException) { - final ExecutionException e = (ExecutionException) _t; - IllegalStateException _illegalStateException = new IllegalStateException(e); - throw _illegalStateException; - } else { - throw Exceptions.sneakyThrow(_t); - } - } - } - String _plus_1 = ("Unsuccessful after " + Integer.valueOf(attempts)); - String _plus_2 = (_plus_1 + " attempts."); - IllegalStateException _illegalStateException_1 = new IllegalStateException(_plus_2); - throw _illegalStateException_1; - } - - public synchronized Promise promiseReply() { - this.device.logger.debug("Promising reply."); - this.promiseLock.lock(); - try { - boolean _equals = Objects.equal(this.messagePromise, null); - if (_equals) { - Promise _newPromise = this.eventExecutor. newPromise(); - this.messagePromise = _newPromise; - return this.messagePromise; - } - return this.messagePromise; - } finally { - this.promiseLock.unlock(); - } - } - - public boolean isNotification(final NetconfMessage message) { - Document _document = message.getDocument(); - final XmlElement xmle = XmlElement.fromDomDocument(_document); - String _name = xmle.getName(); - return XmlNetconfConstants.NOTIFICATION_ELEMENT_NAME.equals(_name); - } } diff --git a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/NetconfDeviceTwoPhaseCommitTransaction.java b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/NetconfDeviceTwoPhaseCommitTransaction.java index a816819cb9..c5390e5409 100644 --- a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/NetconfDeviceTwoPhaseCommitTransaction.java +++ b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/NetconfDeviceTwoPhaseCommitTransaction.java @@ -7,15 +7,21 @@ */ package org.opendaylight.controller.sal.connect.netconf; +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; + import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Map.Entry; -import java.util.Set; -import org.eclipse.xtext.xbase.lib.IterableExtensions; -import org.opendaylight.controller.md.sal.common.api.data.DataModification; import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction; +import org.opendaylight.controller.md.sal.common.api.data.DataModification; import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.common.RpcResult; import org.opendaylight.yangtools.yang.data.api.CompositeNode; @@ -28,18 +34,14 @@ import org.opendaylight.yangtools.yang.data.impl.util.CompositeNodeBuilder; import com.google.common.base.Optional; import com.google.common.base.Preconditions; -import com.google.common.collect.Collections2; import com.google.common.collect.ImmutableList; -import com.google.common.collect.Iterables; import com.google.common.collect.Lists; -import static org.opendaylight.controller.sal.connect.netconf.NetconfMapping.*; - public class NetconfDeviceTwoPhaseCommitTransaction implements DataCommitTransaction { - private NetconfDevice device; + private final NetconfDevice device; private final DataModification modification; - private boolean candidateSupported = true; + private final boolean candidateSupported = true; public NetconfDeviceTwoPhaseCommitTransaction(NetconfDevice device, DataModification modification) { @@ -50,7 +52,7 @@ public class NetconfDeviceTwoPhaseCommitTransaction implements DataCommitTransac public void prepare() { for (InstanceIdentifier toRemove : modification.getRemovedConfigurationData()) { - sendRemove(toRemove); + sendDelete(toRemove); } for(Entry toUpdate : modification.getUpdatedConfigurationData().entrySet()) { sendMerge(toUpdate.getKey(),toUpdate.getValue()); @@ -62,23 +64,23 @@ public class NetconfDeviceTwoPhaseCommitTransaction implements DataCommitTransac sendEditRpc(createEditStructure(key, Optional.absent(), Optional.of(value))); } - private void sendRemove(InstanceIdentifier toRemove) { - sendEditRpc(createEditStructure(toRemove, Optional.of("remove"), Optional. absent())); + private void sendDelete(InstanceIdentifier toDelete) { + sendEditRpc(createEditStructure(toDelete, Optional.of("delete"), Optional. absent())); } private void sendEditRpc(CompositeNode editStructure) { CompositeNodeBuilder builder = configurationRpcBuilder(); builder.setQName(NETCONF_EDIT_CONFIG_QNAME); builder.add(editStructure); - + RpcResult rpcResult = device.invokeRpc(NETCONF_EDIT_CONFIG_QNAME, builder.toInstance()); Preconditions.checkState(rpcResult.isSuccessful(),"Rpc Result was unsuccessful"); - + } private CompositeNodeBuilder configurationRpcBuilder() { CompositeNodeBuilder ret = ImmutableCompositeNode.builder(); - + Node targetNode; if(candidateSupported) { targetNode = ImmutableCompositeNode.create(NETCONF_CANDIDATE_QNAME, ImmutableList.>of()); @@ -90,7 +92,7 @@ public class NetconfDeviceTwoPhaseCommitTransaction implements DataCommitTransac return ret; } - private CompositeNode createEditStructure(InstanceIdentifier dataPath, Optional action, + private CompositeNode createEditStructure(InstanceIdentifier dataPath, Optional operation, Optional lastChildOverride) { List path = dataPath.getPath(); List reversed = Lists.reverse(path); @@ -106,10 +108,10 @@ public class NetconfDeviceTwoPhaseCommitTransaction implements DataCommitTransac for (Entry entry : predicates.entrySet()) { builder.addLeaf(entry.getKey(), entry.getValue()); } - + 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> children = lastChildOverride.get().getChildren(); @@ -118,7 +120,7 @@ public class NetconfDeviceTwoPhaseCommitTransaction implements DataCommitTransac builder.add(child); } } - + } } else { builder.add(previous); @@ -130,7 +132,7 @@ public class NetconfDeviceTwoPhaseCommitTransaction implements DataCommitTransac } @Override - public RpcResult finish() throws IllegalStateException { + public RpcResult finish() { CompositeNodeBuilder commitInput = ImmutableCompositeNode.builder(); commitInput.setQName(NETCONF_COMMIT_QNAME); RpcResult rpcResult = device.invokeRpc(NetconfMapping.NETCONF_COMMIT_QNAME, commitInput.toInstance()); diff --git a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/NetconfMapping.xtend b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/NetconfMapping.xtend index 76a5506df3..f409ecdade 100644 --- a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/NetconfMapping.xtend +++ b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/NetconfMapping.xtend @@ -7,34 +7,39 @@ */ package org.opendaylight.controller.sal.connect.netconf -import org.opendaylight.controller.netconf.api.NetconfMessage -import org.opendaylight.yangtools.yang.data.api.CompositeNode -import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier -import org.opendaylight.yangtools.yang.common.QName -import org.opendaylight.yangtools.yang.common.RpcResult -import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl +import com.google.common.base.Optional +import com.google.common.base.Preconditions +import com.google.common.collect.ImmutableList import java.net.URI -import java.util.Collections -import org.opendaylight.yangtools.yang.data.api.Node -import org.opendaylight.yangtools.yang.data.impl.NodeUtils -import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument -import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates import java.util.ArrayList -import org.opendaylight.yangtools.yang.data.impl.SimpleNodeTOImpl +import java.util.Collections +import java.util.List +import java.util.Set import java.util.concurrent.atomic.AtomicInteger -import org.w3c.dom.Document -import org.w3c.dom.Element import org.opendaylight.controller.sal.common.util.Rpcs -import java.util.List -import com.google.common.collect.ImmutableList -import org.opendaylight.yangtools.yang.data.api.SimpleNode +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.impl.CompositeNodeTOImpl import org.opendaylight.yangtools.yang.data.impl.ImmutableCompositeNode -import com.google.common.base.Preconditions -import com.google.common.base.Optional -import org.opendaylight.yangtools.yang.model.api.SchemaContext +import java.util.Collections +import java.util.List +import java.util.Set +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.impl.CompositeNodeTOImpl import org.opendaylight.yangtools.yang.data.impl.codec.xml.XmlDocumentUtils import org.opendaylight.yangtools.yang.model.api.NotificationDefinition -import java.util.Set +import org.opendaylight.yangtools.yang.model.api.SchemaContext +import org.w3c.dom.Document +import org.w3c.dom.Element +import org.opendaylight.yangtools.yang.common.QName +import org.opendaylight.yangtools.yang.data.impl.SimpleNodeTOImpl +import org.opendaylight.controller.netconf.api.NetconfMessage +import org.opendaylight.yangtools.yang.common.RpcResult class NetconfMapping { @@ -51,7 +56,7 @@ class NetconfMapping { 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"); @@ -93,6 +98,9 @@ class NetconfMapping { 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) } @@ -121,9 +129,9 @@ class NetconfMapping { } static def NetconfMessage toRpcMessage(QName rpc, CompositeNode node,Optional 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); } diff --git a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/NetconfRemoteSchemaSourceProvider.java b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/NetconfRemoteSchemaSourceProvider.java index 49f702080c..fa6b6f7ca5 100644 --- a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/NetconfRemoteSchemaSourceProvider.java +++ b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/NetconfRemoteSchemaSourceProvider.java @@ -9,7 +9,6 @@ package org.opendaylight.controller.sal.connect.netconf; import java.util.Set; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.NetconfState; import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.common.RpcResult; import org.opendaylight.yangtools.yang.data.api.CompositeNode; @@ -19,7 +18,6 @@ import org.opendaylight.yangtools.yang.data.impl.util.CompositeNodeBuilder; import org.opendaylight.yangtools.yang.model.util.repo.SchemaSourceProvider; import com.google.common.base.Optional; -import com.google.common.base.Preconditions; class NetconfRemoteSchemaSourceProvider implements SchemaSourceProvider { diff --git a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/YangModelInputStreamAdapter.java b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/YangModelInputStreamAdapter.java index a34aaff757..23892e18bd 100644 --- a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/YangModelInputStreamAdapter.java +++ b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/YangModelInputStreamAdapter.java @@ -7,16 +7,17 @@ */ package org.opendaylight.controller.sal.connect.netconf; +import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; -import java.io.StringBufferInputStream; -import java.io.StringReader; import org.opendaylight.yangtools.concepts.Delegator; import org.opendaylight.yangtools.yang.common.QName; +import com.google.common.base.Charsets; + /** - * + * * */ public class YangModelInputStreamAdapter extends InputStream implements Delegator { @@ -24,9 +25,7 @@ public class YangModelInputStreamAdapter extends InputStream implements Delegato final String source; final QName moduleIdentifier; final InputStream delegate; - - - + private YangModelInputStreamAdapter(String source, QName moduleIdentifier, InputStream delegate) { super(); this.source = source; @@ -34,46 +33,57 @@ public class YangModelInputStreamAdapter extends InputStream implements Delegato this.delegate = delegate; } + @Override public int read() throws IOException { return delegate.read(); } + @Override public int hashCode() { return delegate.hashCode(); } + @Override public int read(byte[] b) throws IOException { return delegate.read(b); } + @Override public boolean equals(Object obj) { return delegate.equals(obj); } + @Override public int read(byte[] b, int off, int len) throws IOException { return delegate.read(b, off, len); } + @Override public long skip(long n) throws IOException { return delegate.skip(n); } + @Override public int available() throws IOException { return delegate.available(); } + @Override public void close() throws IOException { delegate.close(); } + @Override public void mark(int readlimit) { delegate.mark(readlimit); } + @Override public void reset() throws IOException { delegate.reset(); } + @Override public boolean markSupported() { return delegate.markSupported(); } @@ -89,7 +99,6 @@ public class YangModelInputStreamAdapter extends InputStream implements Delegato } public static YangModelInputStreamAdapter create(QName name, String module) { - InputStream stringInput = new StringBufferInputStream(module); - return new YangModelInputStreamAdapter(null, name, stringInput ); + return new YangModelInputStreamAdapter(null, name, new ByteArrayInputStream(module.getBytes(Charsets.UTF_8))); } } diff --git a/opendaylight/md-sal/sal-netconf-connector/src/main/yang/odl-sal-netconf-connector-cfg.yang b/opendaylight/md-sal/sal-netconf-connector/src/main/yang/odl-sal-netconf-connector-cfg.yang index b28e72eb80..f0fa452dc5 100644 --- a/opendaylight/md-sal/sal-netconf-connector/src/main/yang/odl-sal-netconf-connector-cfg.yang +++ b/opendaylight/md-sal/sal-netconf-connector/src/main/yang/odl-sal-netconf-connector-cfg.yang @@ -92,7 +92,7 @@ module odl-sal-netconf-connector-cfg { leaf connection-timeout-millis { description "Specifies timeout in milliseconds after which connection must be established."; type uint32; - default 5000; + default 20000; } leaf max-connection-attempts { diff --git a/opendaylight/md-sal/sal-remote/pom.xml b/opendaylight/md-sal/sal-remote/pom.xml index b6d0632068..d4f5d43e5e 100644 --- a/opendaylight/md-sal/sal-remote/pom.xml +++ b/opendaylight/md-sal/sal-remote/pom.xml @@ -6,13 +6,20 @@ 1.1-SNAPSHOT sal-remote - jar + bundle scm:git:ssh://git.opendaylight.org:29418/controller.git scm:git:ssh://git.opendaylight.org:29418/controller.git https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL HEAD + + + org.opendaylight.controller + sal-binding-api + 1.1-SNAPSHOT + + @@ -80,12 +87,4 @@ - - - - org.opendaylight.controller - sal-binding-api - 1.1-SNAPSHOT - - diff --git a/opendaylight/md-sal/sal-remote/src/main/java/org/opendaylight/controller/sal/restconf/service/impl/SalRemoteServiceImpl.java b/opendaylight/md-sal/sal-remote/src/main/java/org/opendaylight/controller/sal/restconf/service/impl/SalRemoteServiceImpl.java deleted file mode 100644 index 1da603266b..0000000000 --- a/opendaylight/md-sal/sal-remote/src/main/java/org/opendaylight/controller/sal/restconf/service/impl/SalRemoteServiceImpl.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v1.0 which accompanies this distribution, - * and is available at http://www.eclipse.org/legal/epl-v10.html - */ -package org.opendaylight.controller.sal.restconf.service.impl; - -import java.util.concurrent.Future; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.BeginTransactionOutput; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.CreateDataChangeEventSubscriptionInput; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.CreateDataChangeEventSubscriptionOutput; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.CreateNotificationStreamInput; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.CreateNotificationStreamOutput; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.SalRemoteService; -import org.opendaylight.yangtools.yang.common.RpcResult; - -public class SalRemoteServiceImpl implements SalRemoteService { - @Override - public Future> beginTransaction() { - return null; - } - - @Override - public Future> createDataChangeEventSubscription(CreateDataChangeEventSubscriptionInput input) { - return null; - } - - @Override - public Future> createNotificationStream(CreateNotificationStreamInput input) { - return null; - } -} diff --git a/opendaylight/md-sal/sal-remote/src/main/yang/opendaylight-md-sal-remote.yang b/opendaylight/md-sal/sal-remote/src/main/yang/opendaylight-md-sal-remote.yang index cc77af57d6..d12e252711 100644 --- a/opendaylight/md-sal/sal-remote/src/main/yang/opendaylight-md-sal-remote.yang +++ b/opendaylight/md-sal/sal-remote/src/main/yang/opendaylight-md-sal-remote.yang @@ -9,8 +9,8 @@ module sal-remote { contact "Martin Bobak "; description - "This module contains the definition of types related to - Internet Assigned Numbers Authority. + "This module contains the definition of methods related to + sal remote model. Copyright (c)2013 Cisco Systems, Inc. All rights reserved. @@ -48,8 +48,27 @@ module sal-remote { notification data-changed-notification { description "Data change notification."; - leaf data-change-event { - type instance-identifier; + list data-change-event { + key path; + leaf path { + type instance-identifier; + } + leaf store { + type enumeration { + enum config; + enum operation; + } + } + leaf operation { + type enumeration { + enum created; + enum updated; + enum deleted; + } + } + anyxml data{ + description "DataObject "; + } } } diff --git a/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/config/yang/md/sal/remote/rpc/ZeroMQServerModule.java b/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/config/yang/md/sal/remote/rpc/ZeroMQServerModule.java index f511ff7e76..95bb62f93b 100644 --- a/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/config/yang/md/sal/remote/rpc/ZeroMQServerModule.java +++ b/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/config/yang/md/sal/remote/rpc/ZeroMQServerModule.java @@ -40,8 +40,6 @@ public final class ZeroMQServerModule extends org.opendaylight.controller.config Broker broker = getDomBrokerDependency(); - - final int port = getPort() != null ? getPort() : ZEROMQ_ROUTER_PORT; ServerImpl serverImpl = new ServerImpl(port); @@ -50,7 +48,6 @@ public final class ZeroMQServerModule extends org.opendaylight.controller.config RoutingTableProvider provider = new RoutingTableProvider(bundleContext,serverImpl); - RemoteRpcProvider facade = new RemoteRpcProvider(serverImpl, clientImpl); facade.setRoutingTableProvider(provider ); diff --git a/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/ServerImpl.java b/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/ServerImpl.java index b5a67ff0df..5c14dd0c45 100644 --- a/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/ServerImpl.java +++ b/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/ServerImpl.java @@ -40,6 +40,7 @@ import java.util.concurrent.FutureTask; import java.util.concurrent.TimeUnit; import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; /** * ZeroMq based implementation of RpcRouter. It implements RouteChangeListener of RoutingTable @@ -76,10 +77,6 @@ public class ServerImpl implements RemoteRpcServer, RouteChangeListener();// serverPool = Executors.newSingleThreadExecutor();//main server thread @@ -334,12 +353,13 @@ public class ServerImpl implements RemoteRpcServer, RouteChangeListenergson 2.2.4 + + org.opendaylight.yangtools + yang-parser-impl + + + io.netty + netty-codec-http + 4.0.10.Final + @@ -68,11 +77,6 @@ 1.0.9 test - - org.opendaylight.yangtools - yang-parser-impl - test - org.glassfish.jersey.test-framework.providers jersey-test-framework-provider-grizzly2 diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/api/RestconfService.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/api/RestconfService.java index 848f2c48ab..cef5df9e57 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/api/RestconfService.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/api/RestconfService.java @@ -16,8 +16,10 @@ import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; +import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriInfo; import org.opendaylight.controller.sal.restconf.impl.StructuredData; import org.opendaylight.yangtools.yang.data.api.CompositeNode; @@ -55,11 +57,36 @@ public interface RestconfService { @GET @Path("/modules") - @Produces({Draft02.MediaTypes.API+JSON,Draft02.MediaTypes.API+XML}) + @Produces({Draft02.MediaTypes.API+XML, Draft02.MediaTypes.API+JSON, + MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML}) public StructuredData getModules(); + @GET + @Path("/modules/{identifier:.+}") + @Produces({Draft02.MediaTypes.API+XML, Draft02.MediaTypes.API+JSON, + MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML}) + public StructuredData getModules(@PathParam("identifier") String identifier); + + @GET + @Path("/modules/module/{identifier:.+}") + @Produces({Draft02.MediaTypes.API+XML, Draft02.MediaTypes.API+JSON, + MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML}) + public StructuredData getModule(@PathParam("identifier") String identifier); + + @GET + @Path("/operations") + @Produces({Draft02.MediaTypes.API+XML, Draft02.MediaTypes.API+JSON, + MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML}) + public StructuredData getOperations(); + + @GET + @Path("/operations/{identifier:.+}") + @Produces({Draft02.MediaTypes.API+XML, Draft02.MediaTypes.API+JSON, + MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML}) + public StructuredData getOperations(@PathParam("identifier") String identifier); + @POST - @Path("/operations/{identifier}") + @Path("/operations/{identifier:.+}") @Produces({Draft02.MediaTypes.OPERATION+JSON, Draft02.MediaTypes.OPERATION+XML, Draft02.MediaTypes.DATA+JSON, Draft02.MediaTypes.DATA+XML, MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML}) @@ -69,7 +96,7 @@ public interface RestconfService { public StructuredData invokeRpc(@PathParam("identifier") String identifier, CompositeNode payload); @POST - @Path("/operations/{identifier}") + @Path("/operations/{identifier:.+}") @Produces({Draft02.MediaTypes.OPERATION+JSON, Draft02.MediaTypes.OPERATION+XML, Draft02.MediaTypes.DATA+JSON, Draft02.MediaTypes.DATA+XML, MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML}) @@ -109,4 +136,8 @@ public interface RestconfService { @Path("/config/{identifier:.+}") public Response deleteConfigurationData(@PathParam("identifier") String identifier); + @GET + @Path("/streams/stream/{identifier:.+}") + public Response subscribeToStream(@PathParam("identifier") String identifier, @Context UriInfo uriInfo); + } diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/JsonMapper.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/JsonMapper.java index 226eff44e1..d1441d7b9d 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/JsonMapper.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/JsonMapper.java @@ -203,7 +203,6 @@ class JsonMapper { + baseType.getClass().getSimpleName() + "."); } - // TODO check InstanceIdentifierTypeDefinition if (baseType instanceof IdentityrefTypeDefinition) { if (node.getValue() instanceof QName) { IdentityValuesDTO valueDTO = (IdentityValuesDTO) RestCodec.from(baseType, mountPoint).serialize( diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/RestconfProvider.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/RestconfProvider.java index ea5108ee43..1870bdf0bf 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/RestconfProvider.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/RestconfProvider.java @@ -18,6 +18,7 @@ import org.opendaylight.controller.sal.core.api.model.SchemaService; import org.opendaylight.controller.sal.core.api.mount.MountService; import org.opendaylight.controller.sal.restconf.impl.BrokerFacade; import org.opendaylight.controller.sal.restconf.impl.ControllerContext; +import org.opendaylight.controller.sal.streams.websockets.WebSocketServer; import org.opendaylight.yangtools.concepts.ListenerRegistration; import org.opendaylight.yangtools.yang.model.api.SchemaServiceListener; import org.osgi.framework.BundleActivator; @@ -34,6 +35,7 @@ public class RestconfProvider implements BundleActivator, Provider, ServiceTrack private ServiceTracker brokerServiceTrancker; private BundleContext bundleContext; private ProviderSession session; + private Thread webSocketServerThread; @Override public void onSessionInitiated(ProviderSession session) { @@ -53,6 +55,9 @@ public class RestconfProvider implements BundleActivator, Provider, ServiceTrack bundleContext = context; brokerServiceTrancker = new ServiceTracker<>(context, Broker.class, this); brokerServiceTrancker.open(); + webSocketServerThread = new Thread(new WebSocketServer()); + webSocketServerThread.setName("Web socket server"); + webSocketServerThread.start(); } @Override @@ -64,6 +69,7 @@ public class RestconfProvider implements BundleActivator, Provider, ServiceTrack e.printStackTrace(); } } + webSocketServerThread.interrupt(); session.close(); brokerServiceTrancker.close(); } diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/StructuredDataToJsonProvider.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/StructuredDataToJsonProvider.java index 22e08d97f4..5dba7474ca 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/StructuredDataToJsonProvider.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/StructuredDataToJsonProvider.java @@ -31,8 +31,8 @@ import org.opendaylight.yangtools.yang.model.api.DataNodeContainer; import com.google.gson.stream.JsonWriter; @Provider -@Produces({ Draft02.MediaTypes.DATA + RestconfService.JSON, Draft02.MediaTypes.OPERATION + RestconfService.JSON, - MediaType.APPLICATION_JSON }) +@Produces({ Draft02.MediaTypes.API + RestconfService.JSON, Draft02.MediaTypes.DATA + RestconfService.JSON, + Draft02.MediaTypes.OPERATION + RestconfService.JSON, MediaType.APPLICATION_JSON }) public enum StructuredDataToJsonProvider implements MessageBodyWriter { INSTANCE; diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/StructuredDataToXmlProvider.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/StructuredDataToXmlProvider.java index b6d8c953a9..7d6b329cfa 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/StructuredDataToXmlProvider.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/StructuredDataToXmlProvider.java @@ -37,8 +37,8 @@ import org.slf4j.LoggerFactory; import org.w3c.dom.Document; @Provider -@Produces({ Draft02.MediaTypes.DATA + RestconfService.XML, Draft02.MediaTypes.OPERATION + RestconfService.XML, - MediaType.APPLICATION_XML, MediaType.TEXT_XML }) +@Produces({ Draft02.MediaTypes.API + RestconfService.XML, Draft02.MediaTypes.DATA + RestconfService.XML, + Draft02.MediaTypes.OPERATION + RestconfService.XML, MediaType.APPLICATION_XML, MediaType.TEXT_XML }) public enum StructuredDataToXmlProvider implements MessageBodyWriter { INSTANCE; diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/BrokerFacade.xtend b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/BrokerFacade.xtend index 67429f3759..d3050061da 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/BrokerFacade.xtend +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/BrokerFacade.xtend @@ -11,13 +11,14 @@ import javax.ws.rs.core.Response import org.opendaylight.controller.md.sal.common.api.data.DataReader import org.opendaylight.controller.sal.core.api.Broker.ConsumerSession import org.opendaylight.controller.sal.core.api.data.DataBrokerService +import org.opendaylight.controller.sal.core.api.mount.MountInstance import org.opendaylight.controller.sal.rest.impl.RestconfProvider +import org.opendaylight.controller.sal.streams.listeners.ListenerAdapter 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.slf4j.LoggerFactory -import org.opendaylight.controller.sal.core.api.mount.MountInstance class BrokerFacade implements DataReader { @@ -133,4 +134,13 @@ class BrokerFacade implements DataReader { return transaction.commit } + def registerToListenDataChanges(ListenerAdapter listener) { + checkPreconditions + if (listener.listening) { + return; + } + val registration = dataService.registerDataChangeListener(listener.path, listener) + listener.setRegistration(registration) + } + } diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/ControllerContext.xtend b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/ControllerContext.xtend index 2dfe5062c8..c2b82eae63 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/ControllerContext.xtend +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/ControllerContext.xtend @@ -8,9 +8,11 @@ package org.opendaylight.controller.sal.restconf.impl import com.google.common.base.Preconditions +import com.google.common.base.Splitter import com.google.common.collect.BiMap import com.google.common.collect.FluentIterable import com.google.common.collect.HashBiMap +import com.google.common.collect.Lists import java.net.URI import java.net.URLDecoder import java.net.URLEncoder @@ -86,27 +88,55 @@ class ControllerContext implements SchemaServiceListener { onGlobalContextUpdated(schemas) } - public def InstanceIdWithSchemaNode toInstanceIdentifier(String restconfInstance) { + def InstanceIdWithSchemaNode toInstanceIdentifier(String restconfInstance) { + return restconfInstance.toIdentifier(false) + } + + def InstanceIdWithSchemaNode toMountPointIdentifier(String restconfInstance) { + return restconfInstance.toIdentifier(true) + } + + private def InstanceIdWithSchemaNode toIdentifier(String restconfInstance, boolean toMountPointIdentifier) { checkPreconditions - val pathArgs = restconfInstance.split("/"); + val pathArgs = Lists.newArrayList(Splitter.on("/").split(restconfInstance)) + pathArgs.omitFirstAndLastEmptyString if (pathArgs.empty) { return null; } - if (pathArgs.head.empty) { - pathArgs.remove(0) - } val startModule = pathArgs.head.toModuleName(); if (startModule === null) { throw new ResponseException(BAD_REQUEST, "First node in URI has to be in format \"moduleName:nodeName\"") } - val iiWithSchemaNode = collectPathArguments(InstanceIdentifier.builder(), pathArgs, - globalSchema.getLatestModule(startModule), null); + var InstanceIdWithSchemaNode iiWithSchemaNode = null; + if (toMountPointIdentifier) { + iiWithSchemaNode = collectPathArguments(InstanceIdentifier.builder(), pathArgs, + globalSchema.getLatestModule(startModule), null, true); + } else { + iiWithSchemaNode = collectPathArguments(InstanceIdentifier.builder(), pathArgs, + globalSchema.getLatestModule(startModule), null, false); + } if (iiWithSchemaNode === null) { throw new ResponseException(BAD_REQUEST, "URI has bad format") } return iiWithSchemaNode } + private def omitFirstAndLastEmptyString(List list) { + if (list.empty) { + return list; + } + if (list.head.empty) { + list.remove(0) + } + if (list.empty) { + return list; + } + if (list.last.empty) { + list.remove(list.indexOf(list.last)) + } + return list; + } + private def getLatestModule(SchemaContext schema, String moduleName) { checkArgument(schema !== null); checkArgument(moduleName !== null && !moduleName.empty) @@ -150,31 +180,63 @@ class ControllerContext implements SchemaServiceListener { return moduleSchemas?.filterLatestModule } + def findModuleByNameAndRevision(QName module) { + checkPreconditions + checkArgument(module !== null && module.localName !== null && module.revision !== null) + return globalSchema.findModuleByName(module.localName, module.revision) + } + + def findModuleByNameAndRevision(MountInstance mountPoint, QName module) { + checkPreconditions + checkArgument(module !== null && module.localName !== null && module.revision !== null && mountPoint !== null) + return mountPoint.schemaContext?.findModuleByName(module.localName, module.revision) + } + + def getDataNodeContainerFor(InstanceIdentifier path) { + checkPreconditions + val elements = path.path; + val startQName = elements.head.nodeType; + val initialModule = globalSchema.findModuleByNamespaceAndRevision(startQName.namespace, startQName.revision) + var node = initialModule as DataNodeContainer; + for (element : elements) { + val potentialNode = node.childByQName(element.nodeType); + if (potentialNode === null || !potentialNode.listOrContainer) { + return null + } + node = potentialNode as DataNodeContainer + } + return node + } + def String toFullRestconfIdentifier(InstanceIdentifier path) { checkPreconditions val elements = path.path; val ret = new StringBuilder(); - val startQName = elements.get(0).nodeType; + val startQName = elements.head.nodeType; val initialModule = globalSchema.findModuleByNamespaceAndRevision(startQName.namespace, startQName.revision) - var node = initialModule as DataSchemaNode; + var node = initialModule as DataNodeContainer; for (element : elements) { - node = node.childByQName(element.nodeType); - ret.append(element.toRestconfIdentifier(node)); + val potentialNode = node.childByQName(element.nodeType); + if (!potentialNode.listOrContainer) { + return null + } + node = potentialNode as DataNodeContainer + ret.append(element.convertToRestconfIdentifier(node)); } return ret.toString } - private def dispatch CharSequence toRestconfIdentifier(NodeIdentifier argument, DataSchemaNode node) { + private def dispatch CharSequence convertToRestconfIdentifier(NodeIdentifier argument, ContainerSchemaNode node) { '''/«argument.nodeType.toRestconfIdentifier()»''' } - private def dispatch CharSequence toRestconfIdentifier(NodeIdentifierWithPredicates argument, ListSchemaNode node) { + private def dispatch CharSequence convertToRestconfIdentifier(NodeIdentifierWithPredicates argument, ListSchemaNode node) { val nodeIdentifier = argument.nodeType.toRestconfIdentifier(); val keyValues = argument.keyValues; return '''/«nodeIdentifier»/«FOR key : node.keyDefinition SEPARATOR "/"»«keyValues.get(key).toUriString»«ENDFOR»''' } - private def dispatch CharSequence toRestconfIdentifier(PathArgument argument, DataSchemaNode node) { + private def dispatch CharSequence convertToRestconfIdentifier(PathArgument argument, DataNodeContainer node) { throw new IllegalArgumentException("Conversion of generic path argument is not supported"); } @@ -211,6 +273,16 @@ class ControllerContext implements SchemaServiceListener { return module?.namespace } + def getAllModules(MountInstance mountPoint) { + checkPreconditions + return mountPoint?.schemaContext?.modules + } + + def getAllModules() { + checkPreconditions + return globalSchema.modules + } + def CharSequence toRestconfIdentifier(QName qname) { checkPreconditions var module = uriToModuleName.get(qname.namespace) @@ -253,6 +325,10 @@ class ControllerContext implements SchemaServiceListener { return container.dataNodeChildByQName(name); } + private static dispatch def DataSchemaNode childByQName(Module container, QName name) { + return container.dataNodeChildByQName(name); + } + private static dispatch def DataSchemaNode childByQName(DataSchemaNode container, QName name) { return null; } @@ -281,7 +357,7 @@ class ControllerContext implements SchemaServiceListener { } private def InstanceIdWithSchemaNode collectPathArguments(InstanceIdentifierBuilder builder, List strings, - DataNodeContainer parentNode, MountInstance mountPoint) { + DataNodeContainer parentNode, MountInstance mountPoint, boolean returnJustMountPoint) { checkNotNull(strings) if (parentNode === null) { return null; @@ -318,6 +394,10 @@ class ControllerContext implements SchemaServiceListener { throw new ResponseException(BAD_REQUEST, "Mount point does not contain any schema with modules.") } + if (returnJustMountPoint) { + return new InstanceIdWithSchemaNode(InstanceIdentifier.builder().toInstance, mountPointSchema, mount) + } + if (strings.size == 1) { // any data node is not behind mount point return new InstanceIdWithSchemaNode(InstanceIdentifier.builder().toInstance, mountPointSchema, mount) } @@ -335,7 +415,7 @@ class ControllerContext implements SchemaServiceListener { } return collectPathArguments(InstanceIdentifier.builder(), strings.subList(1, strings.size), - moduleBehindMountPoint, mount); + moduleBehindMountPoint, mount, returnJustMountPoint); } var Module module = null; @@ -375,7 +455,7 @@ class ControllerContext implements SchemaServiceListener { } } - if (!(targetNode instanceof ListSchemaNode) && !(targetNode instanceof ContainerSchemaNode)) { + if (!targetNode.isListOrContainer) { throw new ResponseException(BAD_REQUEST,"URI has bad format. Node \"" + strings.head + "\" must be Container or List yang type.") } // Number of consumed elements @@ -412,7 +492,7 @@ class ControllerContext implements SchemaServiceListener { } if (targetNode instanceof DataNodeContainer) { val remaining = strings.subList(consumed, strings.length); - val result = builder.collectPathArguments(remaining, targetNode as DataNodeContainer, mountPoint); + val result = builder.collectPathArguments(remaining, targetNode as DataNodeContainer, mountPoint, returnJustMountPoint); return result } @@ -498,14 +578,24 @@ class ControllerContext implements SchemaServiceListener { private def QName toQName(String name) { val module = name.toModuleName; val node = name.toNodeName; - val namespace = FluentIterable.from(globalSchema.modules.sort[o1,o2 | o1.revision.compareTo(o2.revision)]) // + val namespace = FluentIterable.from(globalSchema.modules.sort[o1,o2 | o1.revision.compareTo(o2.revision)]) .transform[QName.create(namespace,revision,it.name)].findFirst[module == localName] - ; - return QName.create(namespace,node); + if (namespace === null) { + return null + } + return QName.create(namespace, node); + } + + private def boolean isListOrContainer(DataSchemaNode node) { + return ((node instanceof ListSchemaNode) || (node instanceof ContainerSchemaNode)) } def getRpcDefinition(String name) { - return qnameToRpc.get(name.toQName) + val validName = name.toQName + if (validName === null) { + return null + } + return qnameToRpc.get(validName) } override onGlobalContextUpdated(SchemaContext context) { diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/RestconfImpl.xtend b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/RestconfImpl.xtend index cbfc3edf2c..cfbce736fb 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/RestconfImpl.xtend +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/RestconfImpl.xtend @@ -8,14 +8,22 @@ package org.opendaylight.controller.sal.restconf.impl import com.google.common.base.Preconditions +import com.google.common.base.Splitter +import com.google.common.collect.Lists import java.net.URI +import java.text.ParseException +import java.text.SimpleDateFormat import java.util.ArrayList import java.util.HashMap import java.util.List +import java.util.Set import javax.ws.rs.core.Response +import javax.ws.rs.core.UriInfo import org.opendaylight.controller.md.sal.common.api.TransactionStatus import org.opendaylight.controller.sal.core.api.mount.MountInstance import org.opendaylight.controller.sal.rest.api.RestconfService +import org.opendaylight.controller.sal.streams.listeners.Notificator +import org.opendaylight.controller.sal.streams.websockets.WebSocketServer import org.opendaylight.yangtools.yang.common.QName import org.opendaylight.yangtools.yang.common.RpcResult import org.opendaylight.yangtools.yang.data.api.CompositeNode @@ -34,6 +42,9 @@ import org.opendaylight.yangtools.yang.model.api.RpcDefinition import org.opendaylight.yangtools.yang.model.api.SchemaContext import org.opendaylight.yangtools.yang.model.api.TypeDefinition import org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition +import org.opendaylight.yangtools.yang.model.util.EmptyType +import org.opendaylight.yangtools.yang.parser.builder.impl.ContainerSchemaNodeBuilder +import org.opendaylight.yangtools.yang.parser.builder.impl.LeafSchemaNodeBuilder import static javax.ws.rs.core.Response.Status.* @@ -41,6 +52,17 @@ class RestconfImpl implements RestconfService { val static RestconfImpl INSTANCE = new RestconfImpl val static MOUNT_POINT_MODULE_NAME = "ietf-netconf" + val static REVISION_FORMAT = new SimpleDateFormat("yyyy-MM-dd") + val static RESTCONF_MODULE_DRAFT02_REVISION = "2013-10-19" + val static RESTCONF_MODULE_DRAFT02_NAME = "ietf-restconf" + val static RESTCONF_MODULE_DRAFT02_NAMESPACE = "urn:ietf:params:xml:ns:yang:ietf-restconf" + val static RESTCONF_MODULE_DRAFT02_RESTCONF_GROUPING_SCHEMA_NODE = "restconf" + val static RESTCONF_MODULE_DRAFT02_RESTCONF_CONTAINER_SCHEMA_NODE = "restconf" + val static RESTCONF_MODULE_DRAFT02_MODULES_CONTAINER_SCHEMA_NODE = "modules" + val static RESTCONF_MODULE_DRAFT02_MODULE_LIST_SCHEMA_NODE = "module" + val static RESTCONF_MODULE_DRAFT02_OPERATIONS_CONTAINER_SCHEMA_NODE = "operations" + val static SAL_REMOTE_NAMESPACE = "urn:opendaylight:params:xml:ns:yang:controller:md:sal:remote" + val static SAL_REMOTE_RPC_SUBSRCIBE = "create-data-change-event-subscription" @Property BrokerFacade broker @@ -59,7 +81,148 @@ class RestconfImpl implements RestconfService { } override getModules() { - throw new UnsupportedOperationException("TODO: auto-generated method stub") + val restconfModule = getRestconfModule() + val List> modulesAsData = new ArrayList + val moduleSchemaNode = restconfModule.getSchemaNode(RESTCONF_MODULE_DRAFT02_MODULE_LIST_SCHEMA_NODE) + for (module : allModules) { + modulesAsData.add(module.toModuleCompositeNode(moduleSchemaNode)) + } + val modulesSchemaNode = restconfModule.getSchemaNode(RESTCONF_MODULE_DRAFT02_MODULES_CONTAINER_SCHEMA_NODE) + val modulesNode = NodeFactory.createImmutableCompositeNode(modulesSchemaNode.QName, null, modulesAsData) + return new StructuredData(modulesNode, modulesSchemaNode, null) + } + + override getModules(String identifier) { + var Set modules = null + var MountInstance mountPoint = null + if (identifier.contains(ControllerContext.MOUNT)) { + mountPoint = identifier.toMountPointIdentifier.mountPoint + modules = mountPoint.allModules + } else { + throw new ResponseException(BAD_REQUEST, "URI has bad format. If modules behind mount point should be showed, URI has to end with " + ControllerContext.MOUNT) + } + val List> modulesAsData = new ArrayList + val moduleSchemaNode = restconfModule.getSchemaNode(RESTCONF_MODULE_DRAFT02_MODULE_LIST_SCHEMA_NODE) + for (module : modules) { + modulesAsData.add(module.toModuleCompositeNode(moduleSchemaNode)) + } + val modulesSchemaNode = restconfModule.getSchemaNode(RESTCONF_MODULE_DRAFT02_MODULES_CONTAINER_SCHEMA_NODE) + val modulesNode = NodeFactory.createImmutableCompositeNode(modulesSchemaNode.QName, null, modulesAsData) + return new StructuredData(modulesNode, modulesSchemaNode, mountPoint) + } + + override getModule(String identifier) { + val moduleNameAndRevision = identifier.moduleNameAndRevision + var Module module = null + var MountInstance mountPoint = null + if (identifier.contains(ControllerContext.MOUNT)) { + mountPoint = identifier.toMountPointIdentifier.mountPoint + module = mountPoint.findModuleByNameAndRevision(moduleNameAndRevision) + } else { + module = findModuleByNameAndRevision(moduleNameAndRevision) + } + if (module === null) { + throw new ResponseException(BAD_REQUEST, + "Module with name '" + moduleNameAndRevision.localName + "' and revision '" + + moduleNameAndRevision.revision + "' was not found.") + } + val moduleSchemaNode = restconfModule.getSchemaNode(RESTCONF_MODULE_DRAFT02_MODULE_LIST_SCHEMA_NODE) + val moduleNode = module.toModuleCompositeNode(moduleSchemaNode) + return new StructuredData(moduleNode, moduleSchemaNode, mountPoint) + } + + override getOperations() { + return operationsFromModulesToStructuredData(allModules,null) + } + + override getOperations(String identifier) { + var Set modules = null + var MountInstance mountPoint = null + if (identifier.contains(ControllerContext.MOUNT)) { + mountPoint = identifier.toMountPointIdentifier.mountPoint + modules = mountPoint.allModules + } else { + throw new ResponseException(BAD_REQUEST, "URI has bad format. If operations behind mount point should be showed, URI has to end with " + ControllerContext.MOUNT) + } + return operationsFromModulesToStructuredData(modules,mountPoint) + } + + private def StructuredData operationsFromModulesToStructuredData(Set modules,MountInstance mountPoint) { + val List> operationsAsData = new ArrayList + val operationsSchemaNode = restconfModule.getSchemaNode(RESTCONF_MODULE_DRAFT02_OPERATIONS_CONTAINER_SCHEMA_NODE) + val fakeOperationsSchemaNode = new ContainerSchemaNodeBuilder(RESTCONF_MODULE_DRAFT02_NAME, 0, operationsSchemaNode.QName, operationsSchemaNode.path) + for (module : modules) { + for (rpc : module.rpcs) { + operationsAsData.add(NodeFactory.createImmutableSimpleNode(rpc.QName, null, null)) + val fakeRpcSchemaNode = new LeafSchemaNodeBuilder(module.name, 0, rpc.QName, null) + fakeRpcSchemaNode.setAugmenting(true) + fakeRpcSchemaNode.setType(EmptyType.instance) + fakeOperationsSchemaNode.addChildNode(fakeRpcSchemaNode.build) + } + } + val operationsNode = NodeFactory.createImmutableCompositeNode(operationsSchemaNode.QName, null, operationsAsData) + return new StructuredData(operationsNode, fakeOperationsSchemaNode.build, mountPoint) + } + + private def Module getRestconfModule() { + val restconfModule = findModuleByNameAndRevision( + QName.create(RESTCONF_MODULE_DRAFT02_NAMESPACE, RESTCONF_MODULE_DRAFT02_REVISION, + RESTCONF_MODULE_DRAFT02_NAME)) + if (restconfModule === null) { + throw new ResponseException(INTERNAL_SERVER_ERROR, "Restconf module was not found.") + } + return restconfModule + } + + private def QName getModuleNameAndRevision(String identifier) { + val indexOfMountPointFirstLetter = identifier.indexOf(ControllerContext.MOUNT) + var moduleNameAndRevision = ""; + if (indexOfMountPointFirstLetter !== -1) { // module and revision is behind mount point string + moduleNameAndRevision = identifier.substring(indexOfMountPointFirstLetter + ControllerContext.MOUNT.length) + } else ( + moduleNameAndRevision = identifier + ) + val pathArgs = Lists.newArrayList(Splitter.on("/").omitEmptyStrings.split(moduleNameAndRevision)) + if (pathArgs.length < 2) { + throw new ResponseException(BAD_REQUEST, + "URI has bad format. End of URI should be in format 'moduleName/yyyy-MM-dd'") + } + try { + val moduleName = pathArgs.head + val moduleRevision = REVISION_FORMAT.parse(pathArgs.get(1)) + return QName.create(null, moduleRevision, moduleName) + } catch(ParseException e) { + throw new ResponseException(BAD_REQUEST, "URI has bad format. It should be 'moduleName/yyyy-MM-dd'") + } + } + + private def CompositeNode toModuleCompositeNode(Module module, DataSchemaNode moduleSchemaNode) { + val List> moduleNodeValues = new ArrayList + val nameSchemaNode = (moduleSchemaNode as DataNodeContainer).findInstanceDataChildrenByName("name").head + moduleNodeValues.add(NodeFactory.createImmutableSimpleNode(nameSchemaNode.QName, null, module.name)) + val revisionSchemaNode = (moduleSchemaNode as DataNodeContainer).findInstanceDataChildrenByName("revision").head + moduleNodeValues.add(NodeFactory.createImmutableSimpleNode(revisionSchemaNode.QName, null, REVISION_FORMAT.format(module.revision))) + val namespaceSchemaNode = (moduleSchemaNode as DataNodeContainer).findInstanceDataChildrenByName("namespace").head + moduleNodeValues.add(NodeFactory.createImmutableSimpleNode(namespaceSchemaNode.QName, null, module.namespace.toString)) + val featureSchemaNode = (moduleSchemaNode as DataNodeContainer).findInstanceDataChildrenByName("feature").head + for (feature : module.features) { + moduleNodeValues.add(NodeFactory.createImmutableSimpleNode(featureSchemaNode.QName, null, feature.QName.localName)) + } + return NodeFactory.createImmutableCompositeNode(moduleSchemaNode.QName, null, moduleNodeValues) + } + + private def DataSchemaNode getSchemaNode(Module restconfModule, String schemaNodeName) { + val restconfGrouping = restconfModule.groupings.filter[g|g.QName.localName == RESTCONF_MODULE_DRAFT02_RESTCONF_GROUPING_SCHEMA_NODE].head + val restconfContainer = restconfGrouping.findInstanceDataChildrenByName(RESTCONF_MODULE_DRAFT02_RESTCONF_CONTAINER_SCHEMA_NODE).head + if (schemaNodeName == RESTCONF_MODULE_DRAFT02_OPERATIONS_CONTAINER_SCHEMA_NODE) { + return (restconfContainer as DataNodeContainer).findInstanceDataChildrenByName(RESTCONF_MODULE_DRAFT02_OPERATIONS_CONTAINER_SCHEMA_NODE).head + } else if (schemaNodeName == RESTCONF_MODULE_DRAFT02_MODULES_CONTAINER_SCHEMA_NODE) { + return (restconfContainer as DataNodeContainer).findInstanceDataChildrenByName(RESTCONF_MODULE_DRAFT02_MODULES_CONTAINER_SCHEMA_NODE).head + } else if (schemaNodeName == RESTCONF_MODULE_DRAFT02_MODULE_LIST_SCHEMA_NODE) { + val modules = (restconfContainer as DataNodeContainer).findInstanceDataChildrenByName(RESTCONF_MODULE_DRAFT02_MODULES_CONTAINER_SCHEMA_NODE).head + return (modules as DataNodeContainer).findInstanceDataChildrenByName(RESTCONF_MODULE_DRAFT02_MODULE_LIST_SCHEMA_NODE).head + } + return null } override getRoot() { @@ -67,6 +230,36 @@ class RestconfImpl implements RestconfService { } override invokeRpc(String identifier, CompositeNode payload) { + val rpc = identifier.rpcDefinition + if (rpc === null) { + throw new ResponseException(NOT_FOUND, "RPC does not exist."); + } + if (rpc.QName.namespace.toString == SAL_REMOTE_NAMESPACE && rpc.QName.localName == SAL_REMOTE_RPC_SUBSRCIBE) { + val value = normalizeNode(payload, rpc.input, null) + val pathNode = value?.getFirstSimpleByName(QName.create(rpc.QName, "path")) + val pathValue = pathNode?.value + if (pathValue === null && !(pathValue instanceof InstanceIdentifier)) { + throw new ResponseException(INTERNAL_SERVER_ERROR, "Instance identifier was not normalized correctly."); + } + val pathIdentifier = (pathValue as InstanceIdentifier) + var String streamName = null + if (!pathIdentifier.path.nullOrEmpty) { + streamName = Notificator.createStreamNameFromUri(pathIdentifier.toFullRestconfIdentifier) + } + if (streamName.nullOrEmpty) { + throw new ResponseException(BAD_REQUEST, "Path is empty or contains data node which is not Container or List build-in type."); + } + val streamNameNode = NodeFactory.createImmutableSimpleNode(QName.create(rpc.output.QName, "stream-name"), null, streamName) + val List> output = new ArrayList + output.add(streamNameNode) + val responseData = NodeFactory.createMutableCompositeNode(rpc.output.QName, null, output, null, null) + + if (!Notificator.existListenerFor(pathIdentifier)) { + Notificator.createListener(pathIdentifier, streamName) + } + + return new StructuredData(responseData, rpc.output, null) + } return callRpc(identifier.rpcDefinition, payload) } @@ -224,6 +417,21 @@ class RestconfImpl implements RestconfService { } } + override subscribeToStream(String identifier, UriInfo uriInfo) { + val streamName = Notificator.createStreamNameFromUri(identifier) + if (streamName.nullOrEmpty) { + throw new ResponseException(BAD_REQUEST, "Stream name is empty.") + } + val listener = Notificator.getListenerFor(streamName); + if (listener === null) { + throw new ResponseException(BAD_REQUEST, "Stream was not found.") + } + broker.registerToListenDataChanges(listener) + val uriBuilder = uriInfo.getAbsolutePathBuilder() + val uriToWebsocketServer = uriBuilder.port(WebSocketServer.PORT).replacePath(streamName).build() + return Response.status(OK).location(uriToWebsocketServer).build + } + private def dispatch URI namespace(CompositeNode data) { return data.nodeType.namespace } diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/streams/listeners/ListenerAdapter.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/streams/listeners/ListenerAdapter.java new file mode 100644 index 0000000000..fdd6ba0317 --- /dev/null +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/streams/listeners/ListenerAdapter.java @@ -0,0 +1,406 @@ +package org.opendaylight.controller.sal.streams.listeners; + +import io.netty.channel.Channel; +import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; +import io.netty.util.internal.ConcurrentSet; + +import java.io.ByteArrayOutputStream; +import java.io.OutputStreamWriter; +import java.io.UnsupportedEncodingException; +import java.text.SimpleDateFormat; +import java.util.Collection; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Random; +import java.util.Set; +import java.util.concurrent.Executors; + +import javax.activation.UnsupportedDataTypeException; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +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.md.sal.common.api.data.DataChangeEvent; +import org.opendaylight.controller.sal.core.api.data.DataChangeListener; +import org.opendaylight.controller.sal.rest.impl.XmlMapper; +import org.opendaylight.controller.sal.restconf.impl.ControllerContext; +import org.opendaylight.yangtools.concepts.ListenerRegistration; +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.NodeWithValue; +import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument; +import org.opendaylight.yangtools.yang.model.api.DataNodeContainer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + +import com.google.common.base.Preconditions; +import com.google.common.eventbus.AsyncEventBus; +import com.google.common.eventbus.EventBus; +import com.google.common.eventbus.Subscribe; + +public class ListenerAdapter implements DataChangeListener { + + private static final Logger logger = LoggerFactory.getLogger(ListenerAdapter.class); + private final XmlMapper xmlMapper = new XmlMapper(); + private final SimpleDateFormat rfc3339 = new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ssZ"); + + private final InstanceIdentifier path; + private ListenerRegistration registration; + private final String streamName; + private Set subscribers = new ConcurrentSet<>(); + private final EventBus eventBus; + private final EventBusChangeRecorder eventBusChangeRecorder; + + ListenerAdapter(InstanceIdentifier path, String streamName) { + Preconditions.checkNotNull(path); + Preconditions.checkArgument(streamName != null && !streamName.isEmpty()); + this.path = path; + this.streamName = streamName; + eventBus = new AsyncEventBus(Executors.newSingleThreadExecutor()); + eventBusChangeRecorder = new EventBusChangeRecorder(); + eventBus.register(eventBusChangeRecorder); + } + + @Override + public void onDataChanged(DataChangeEvent change) { + if (!change.getCreatedConfigurationData().isEmpty() || !change.getCreatedOperationalData().isEmpty() + || !change.getUpdatedConfigurationData().isEmpty() || !change.getUpdatedOperationalData().isEmpty() + || !change.getRemovedConfigurationData().isEmpty() || !change.getRemovedOperationalData().isEmpty()) { + String xml = prepareXmlFrom(change); + Event event = new Event(EventType.NOTIFY); + event.setData(xml); + eventBus.post(event); + } + } + + private final class EventBusChangeRecorder { + @Subscribe public void recordCustomerChange(Event event) { + if (event.getType() == EventType.REGISTER) { + Channel subscriber = event.getSubscriber(); + if (!subscribers.contains(subscriber)) { + subscribers.add(subscriber); + } + } else if (event.getType() == EventType.DEREGISTER) { + subscribers.remove(event.getSubscriber()); + Notificator.removeListenerIfNoSubscriberExists(ListenerAdapter.this); + } else if (event.getType() == EventType.NOTIFY) { + for (Channel subscriber : subscribers) { + if (subscriber.isActive()) { + logger.debug("Data are sent to subscriber {}:", subscriber.remoteAddress()); + subscriber.writeAndFlush(new TextWebSocketFrame(event.getData())); + } else { + logger.debug("Subscriber {} is removed - channel is not active yet.", subscriber.remoteAddress()); + subscribers.remove(subscriber); + } + } + } + } + } + + private final class Event { + private final EventType type; + private Channel subscriber; + private String data; + + public Event(EventType type) { + this.type = type; + } + + public Channel getSubscriber() { + return subscriber; + } + + public void setSubscriber(Channel subscriber) { + this.subscriber = subscriber; + } + + public String getData() { + return data; + } + + public void setData(String data) { + this.data = data; + } + + public EventType getType() { + return type; + } + } + + private enum EventType { + REGISTER, + DEREGISTER, + NOTIFY; + } + + private String prepareXmlFrom(DataChangeEvent change) { + Document doc = createDocument(); + Element notificationElement = doc.createElementNS("urn:ietf:params:xml:ns:netconf:notification:1.0", + "notification"); + doc.appendChild(notificationElement); + + Element eventTimeElement = doc.createElement("eventTime"); + eventTimeElement.setTextContent(toRFC3339(new Date())); + notificationElement.appendChild(eventTimeElement); + + Element dataChangedNotificationEventElement = doc.createElementNS( + "urn:opendaylight:params:xml:ns:yang:controller:md:sal:remote", "data-changed-notification"); + addValuesToDataChangedNotificationEventElement(doc, dataChangedNotificationEventElement, change); + notificationElement.appendChild(dataChangedNotificationEventElement); + + try { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + TransformerFactory tf = TransformerFactory.newInstance(); + Transformer transformer = tf.newTransformer(); + transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no"); + transformer.setOutputProperty(OutputKeys.METHOD, "xml"); + transformer.setOutputProperty(OutputKeys.INDENT, "yes"); + transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); + transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4"); + transformer.transform(new DOMSource(doc), new StreamResult(new OutputStreamWriter(out, "UTF-8"))); + byte[] charData = out.toByteArray(); + return new String(charData, "UTF-8"); + } catch (TransformerException | UnsupportedEncodingException e) { + String msg = "Error during transformation of Document into String"; + logger.error(msg, e); + return msg; + } + } + + private String toRFC3339(Date d) { + return rfc3339.format(d).replaceAll("(\\d\\d)(\\d\\d)$", "$1:$2"); + } + + private Document createDocument() { + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + Document doc = null; + try { + DocumentBuilder bob = dbf.newDocumentBuilder(); + doc = bob.newDocument(); + } catch (ParserConfigurationException e) { + return null; + } + return doc; + } + + private void addValuesToDataChangedNotificationEventElement(Document doc, + Element dataChangedNotificationEventElement, DataChangeEvent change) { + addValuesFromDataToElement(doc, change.getCreatedConfigurationData(), dataChangedNotificationEventElement, Store.CONFIG, Operation.CREATED); + addValuesFromDataToElement(doc, change.getCreatedOperationalData(), dataChangedNotificationEventElement, Store.OPERATION, Operation.CREATED); + if (change.getCreatedConfigurationData().isEmpty()) { + addValuesFromDataToElement(doc, change.getUpdatedConfigurationData(), dataChangedNotificationEventElement, Store.CONFIG, Operation.UPDATED); + } + if (change.getCreatedOperationalData().isEmpty()) { + addValuesFromDataToElement(doc, change.getUpdatedOperationalData(), dataChangedNotificationEventElement, Store.OPERATION, Operation.UPDATED); + } + addValuesFromDataToElement(doc, change.getRemovedConfigurationData(), dataChangedNotificationEventElement, Store.CONFIG, Operation.DELETED); + addValuesFromDataToElement(doc, change.getRemovedOperationalData(), dataChangedNotificationEventElement, Store.OPERATION, Operation.DELETED); + } + + private void addValuesFromDataToElement(Document doc, Set data, Element element, Store store, + Operation operation) { + if (data == null || data.isEmpty()) { + return; + } + for (InstanceIdentifier path : data) { + Node node = createDataChangeEventElement(doc, path, null, store, operation); + element.appendChild(node); + } + } + + private void addValuesFromDataToElement(Document doc, Map data, Element element, Store store, + Operation operation) { + if (data == null || data.isEmpty()) { + return; + } + for (Entry entry : data.entrySet()) { + Node node = createDataChangeEventElement(doc, entry.getKey(), entry.getValue(), store, operation); + element.appendChild(node); + } + } + + private Node createDataChangeEventElement(Document doc, InstanceIdentifier path, CompositeNode data, Store store, + Operation operation) { + Element dataChangeEventElement = doc.createElement("data-change-event"); + + Element pathElement = doc.createElement("path"); + addPathAsValueToElement(path, pathElement); + dataChangeEventElement.appendChild(pathElement); + + Element storeElement = doc.createElement("store"); + storeElement.setTextContent(store.value); + dataChangeEventElement.appendChild(storeElement); + + Element operationElement = doc.createElement("operation"); + operationElement.setTextContent(operation.value); + dataChangeEventElement.appendChild(operationElement); + + if (data != null) { + Element dataElement = doc.createElement("data"); + Node dataAnyXml = translateToXml(path, data); + Node adoptedNode = doc.adoptNode(dataAnyXml); + dataElement.appendChild(adoptedNode); + dataChangeEventElement.appendChild(dataElement); + } + + return dataChangeEventElement; + } + + private Node translateToXml(InstanceIdentifier path, CompositeNode data) { + DataNodeContainer schemaNode = ControllerContext.getInstance().getDataNodeContainerFor(path); + if (schemaNode == null) { + logger.info("Path '{}' contains node with unsupported type (supported type is Container or List) or some node was not found.", path); + return null; + } + try { + Document xml = xmlMapper.write(data, schemaNode); + return xml.getFirstChild(); + } catch (UnsupportedDataTypeException e) { + logger.error("Error occured during translation of notification to XML.", e); + return null; + } + } + + private void addPathAsValueToElement(InstanceIdentifier path, Element element) { + // Map< key = namespace, value = prefix> + Map prefixes = new HashMap<>(); + InstanceIdentifier instanceIdentifier = path; + StringBuilder textContent = new StringBuilder(); + for (PathArgument pathArgument : instanceIdentifier.getPath()) { + textContent.append("/"); + writeIdentifierWithNamespacePrefix(element, textContent, pathArgument.getNodeType(), prefixes); + if (pathArgument instanceof NodeIdentifierWithPredicates) { + Map predicates = ((NodeIdentifierWithPredicates) pathArgument).getKeyValues(); + for (QName keyValue : predicates.keySet()) { + String predicateValue = String.valueOf(predicates.get(keyValue)); + textContent.append("["); + writeIdentifierWithNamespacePrefix(element, textContent, keyValue, prefixes); + textContent.append("='"); + textContent.append(predicateValue); + textContent.append("'"); + textContent.append("]"); + } + } else if (pathArgument instanceof NodeWithValue) { + textContent.append("[.='"); + textContent.append(((NodeWithValue)pathArgument).getValue()); + textContent.append("'"); + textContent.append("]"); + } + } + element.setTextContent(textContent.toString()); + } + + private static void writeIdentifierWithNamespacePrefix(Element element, StringBuilder textContent, QName qName, + Map prefixes) { + String namespace = qName.getNamespace().toString(); + String prefix = prefixes.get(namespace); + if (prefix == null) { + prefix = qName.getPrefix(); + if (prefix == null || prefix.isEmpty() || prefixes.containsValue(prefix)) { + prefix = generateNewPrefix(prefixes.values()); + } + } + + element.setAttribute("xmlns:" + prefix, namespace.toString()); + textContent.append(prefix); + prefixes.put(namespace, prefix); + + textContent.append(":"); + textContent.append(qName.getLocalName()); + } + + private static String generateNewPrefix(Collection prefixes) { + StringBuilder result = null; + Random random = new Random(); + do { + result = new StringBuilder(); + for (int i = 0; i < 4; i++) { + int randomNumber = 0x61 + (Math.abs(random.nextInt()) % 26); + result.append(Character.toChars(randomNumber)); + } + } while (prefixes.contains(result.toString())); + + return result.toString(); + } + + public InstanceIdentifier getPath() { + return path; + } + + public void setRegistration(ListenerRegistration registration) { + this.registration = registration; + } + + public String getStreamName() { + return streamName; + } + + public void close() throws Exception { + subscribers = new ConcurrentSet<>(); + registration.close(); + registration = null; + eventBus.unregister(eventBusChangeRecorder); + } + + public boolean isListening() { + return registration == null ? false : true; + } + + public void addSubscriber(Channel subscriber) { + if (!subscriber.isActive()) { + logger.debug("Channel is not active between websocket server and subscriber {}" + + subscriber.remoteAddress()); + } + Event event = new Event(EventType.REGISTER); + event.setSubscriber(subscriber); + eventBus.post(event); + } + + public void removeSubscriber(Channel subscriber) { + logger.debug("Subscriber {} is removed.", subscriber.remoteAddress()); + Event event = new Event(EventType.DEREGISTER); + event.setSubscriber(subscriber); + eventBus.post(event); + } + + public boolean hasSubscribers() { + return !subscribers.isEmpty(); + } + + private static enum Store { + CONFIG("config"), + OPERATION("operation"); + + private final String value; + + private Store(String value) { + this.value = value; + } + } + + private static enum Operation { + CREATED("created"), + UPDATED("updated"), + DELETED("deleted"); + + private final String value; + + private Operation(String value) { + this.value = value; + } + } + +} diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/streams/listeners/Notificator.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/streams/listeners/Notificator.java new file mode 100644 index 0000000000..d1cb25861a --- /dev/null +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/streams/listeners/Notificator.java @@ -0,0 +1,100 @@ +package org.opendaylight.controller.sal.streams.listeners; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier; + +public class Notificator { + + private static Map listenersByStreamName = new ConcurrentHashMap<>(); + private static Map listenersByInstanceIdentifier = new ConcurrentHashMap<>(); + private static final Lock lock = new ReentrantLock(); + + private Notificator() { + } + + public static ListenerAdapter getListenerFor(String streamName) { + return listenersByStreamName.get(streamName); + } + + public static ListenerAdapter getListenerFor(InstanceIdentifier path) { + return listenersByInstanceIdentifier.get(path); + } + + public static boolean existListenerFor(InstanceIdentifier path) { + return listenersByInstanceIdentifier.containsKey(path); + } + + public static ListenerAdapter createListener(InstanceIdentifier path, String streamName) { + ListenerAdapter listener = new ListenerAdapter(path, streamName); + try { + lock.lock(); + listenersByInstanceIdentifier.put(path, listener); + listenersByStreamName.put(streamName, listener); + } finally { + lock.unlock(); + } + return listener; + } + + public static void removeListener(InstanceIdentifier path) { + ListenerAdapter listener = listenersByInstanceIdentifier.get(path); + deleteListener(listener); + } + + public static String createStreamNameFromUri(String uri) { + if (uri == null) { + return null; + } + String result = uri; + if (result.startsWith("/")) { + result = result.substring(1); + } + if (result.endsWith("/")) { + result = result.substring(0, result.length()); + } + return result; + } + + public static void removeAllListeners() { + for (ListenerAdapter listener : listenersByInstanceIdentifier.values()) { + try { + listener.close(); + } catch (Exception e) { + } + } + try { + lock.lock(); + listenersByStreamName = new ConcurrentHashMap<>(); + listenersByInstanceIdentifier = new ConcurrentHashMap<>(); + } finally { + lock.unlock(); + } + } + + public static void removeListenerIfNoSubscriberExists(ListenerAdapter listener) { + if (!listener.hasSubscribers()) { + deleteListener(listener); + } + } + + private static void deleteListener(ListenerAdapter listener) { + if (listener != null) { + try { + listener.close(); + } catch (Exception e) { + } + try { + lock.lock(); + listenersByInstanceIdentifier.remove(listener.getPath()); + listenersByStreamName.remove(listener.getStreamName()); + } finally { + lock.unlock(); + } + } + } + +} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/streams/websockets/WebSocketServer.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/streams/websockets/WebSocketServer.java new file mode 100644 index 0000000000..142cde1400 --- /dev/null +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/streams/websockets/WebSocketServer.java @@ -0,0 +1,52 @@ +package org.opendaylight.controller.sal.streams.websockets; + +import org.opendaylight.controller.sal.streams.listeners.Notificator; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import io.netty.bootstrap.ServerBootstrap; +import io.netty.channel.Channel; +import io.netty.channel.EventLoopGroup; +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.channel.socket.nio.NioServerSocketChannel; + +public class WebSocketServer implements Runnable { + + private static final Logger logger = LoggerFactory.getLogger(WebSocketServer.class); + + public static final int PORT = 8181; + private EventLoopGroup bossGroup; + private EventLoopGroup workerGroup; + + @Override + public void run() { + bossGroup = new NioEventLoopGroup(); + workerGroup = new NioEventLoopGroup(); + try { + ServerBootstrap b = new ServerBootstrap(); + b.group(bossGroup, workerGroup) + .channel(NioServerSocketChannel.class) + .childHandler(new WebSocketServerInitializer()); + + Channel ch = b.bind(PORT).sync().channel(); + logger.info("Web socket server started at port {}.", PORT); + + ch.closeFuture().sync(); + } catch (InterruptedException e) { + // NOOP + } finally { + stop(); + } + } + + private void stop() { + Notificator.removeAllListeners(); + if (bossGroup != null) { + bossGroup.shutdownGracefully(); + } + if (workerGroup != null) { + workerGroup.shutdownGracefully(); + } + } + +} diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/streams/websockets/WebSocketServerHandler.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/streams/websockets/WebSocketServerHandler.java new file mode 100644 index 0000000000..618ee57aba --- /dev/null +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/streams/websockets/WebSocketServerHandler.java @@ -0,0 +1,134 @@ +package org.opendaylight.controller.sal.streams.websockets; + +import static io.netty.handler.codec.http.HttpHeaders.isKeepAlive; +import static io.netty.handler.codec.http.HttpHeaders.setContentLength; +import static io.netty.handler.codec.http.HttpHeaders.Names.HOST; +import static io.netty.handler.codec.http.HttpMethod.GET; +import static io.netty.handler.codec.http.HttpResponseStatus.BAD_REQUEST; +import static io.netty.handler.codec.http.HttpResponseStatus.FORBIDDEN; +import static io.netty.handler.codec.http.HttpResponseStatus.INTERNAL_SERVER_ERROR; +import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelFutureListener; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.SimpleChannelInboundHandler; +import io.netty.handler.codec.http.DefaultFullHttpResponse; +import io.netty.handler.codec.http.FullHttpRequest; +import io.netty.handler.codec.http.FullHttpResponse; +import io.netty.handler.codec.http.HttpRequest; +import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame; +import io.netty.handler.codec.http.websocketx.PingWebSocketFrame; +import io.netty.handler.codec.http.websocketx.PongWebSocketFrame; +import io.netty.handler.codec.http.websocketx.WebSocketFrame; +import io.netty.handler.codec.http.websocketx.WebSocketServerHandshaker; +import io.netty.handler.codec.http.websocketx.WebSocketServerHandshakerFactory; +import io.netty.util.CharsetUtil; + +import java.io.IOException; + +import org.opendaylight.controller.sal.streams.listeners.ListenerAdapter; +import org.opendaylight.controller.sal.streams.listeners.Notificator; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class WebSocketServerHandler extends SimpleChannelInboundHandler { + + private static final Logger logger = LoggerFactory.getLogger(WebSocketServerHandler.class); + + private WebSocketServerHandshaker handshaker; + + @Override + protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception { + if (msg instanceof FullHttpRequest) { + handleHttpRequest(ctx, (FullHttpRequest) msg); + } else if (msg instanceof WebSocketFrame) { + handleWebSocketFrame(ctx, (WebSocketFrame) msg); + } + } + + private void handleHttpRequest(ChannelHandlerContext ctx, FullHttpRequest req) + throws Exception { + // Handle a bad request. + if (!req.getDecoderResult().isSuccess()) { + sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HTTP_1_1, BAD_REQUEST)); + return; + } + + // Allow only GET methods. + if (req.getMethod() != GET) { + sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HTTP_1_1, FORBIDDEN)); + return; + } + + String streamName = Notificator.createStreamNameFromUri(req.getUri()); + ListenerAdapter listener = Notificator.getListenerFor(streamName); + if (listener != null) { + listener.addSubscriber(ctx.channel()); + logger.debug("Subscriber successfully registered."); + } else { + logger.error("Listener for stream with name '{}' was not found.", streamName); + sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HTTP_1_1, INTERNAL_SERVER_ERROR)); + } + + // Handshake + WebSocketServerHandshakerFactory wsFactory = new WebSocketServerHandshakerFactory( + getWebSocketLocation(req), null, false); + handshaker = wsFactory.newHandshaker(req); + if (handshaker == null) { + WebSocketServerHandshakerFactory.sendUnsupportedWebSocketVersionResponse(ctx.channel()); + } else { + handshaker.handshake(ctx.channel(), req); + } + + } + + private static void sendHttpResponse(ChannelHandlerContext ctx, + HttpRequest req, FullHttpResponse res) { + // Generate an error page if response getStatus code is not OK (200). + if (res.getStatus().code() != 200) { + ByteBuf buf = Unpooled.copiedBuffer(res.getStatus().toString(), CharsetUtil.UTF_8); + res.content().writeBytes(buf); + buf.release(); + setContentLength(res, res.content().readableBytes()); + } + + // Send the response and close the connection if necessary. + ChannelFuture f = ctx.channel().writeAndFlush(res); + if (!isKeepAlive(req) || res.getStatus().code() != 200) { + f.addListener(ChannelFutureListener.CLOSE); + } + } + + private void handleWebSocketFrame(ChannelHandlerContext ctx, WebSocketFrame frame) throws IOException { + if (frame instanceof CloseWebSocketFrame) { + handshaker.close(ctx.channel(), (CloseWebSocketFrame) frame.retain()); + String streamName = Notificator.createStreamNameFromUri(((CloseWebSocketFrame) frame).reasonText()); + ListenerAdapter listener = Notificator.getListenerFor(streamName); + if (listener != null) { + listener.removeSubscriber(ctx.channel()); + logger.debug("Subscriber successfully registered."); + } + Notificator.removeListenerIfNoSubscriberExists(listener); + return; + } else if (frame instanceof PingWebSocketFrame) { + ctx.channel().write(new PongWebSocketFrame(frame.content().retain())); + return; + } + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) + throws Exception { + if (cause instanceof java.nio.channels.ClosedChannelException == false) { + //cause.printStackTrace(); + } + ctx.close(); + } + + private static String getWebSocketLocation(HttpRequest req) { + return "http://" + req.headers().get(HOST) + req.getUri(); + } + +} diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/streams/websockets/WebSocketServerInitializer.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/streams/websockets/WebSocketServerInitializer.java new file mode 100644 index 0000000000..5eb71ef491 --- /dev/null +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/streams/websockets/WebSocketServerInitializer.java @@ -0,0 +1,19 @@ +package org.opendaylight.controller.sal.streams.websockets; + +import io.netty.channel.ChannelInitializer; +import io.netty.channel.ChannelPipeline; +import io.netty.channel.socket.SocketChannel; +import io.netty.handler.codec.http.HttpObjectAggregator; +import io.netty.handler.codec.http.HttpServerCodec; + +public class WebSocketServerInitializer extends ChannelInitializer { + + @Override + protected void initChannel(SocketChannel ch) throws Exception { + ChannelPipeline pipeline = ch.pipeline(); + pipeline.addLast("codec-http", new HttpServerCodec()); + pipeline.addLast("aggregator", new HttpObjectAggregator(65536)); + pipeline.addLast("handler", new WebSocketServerHandler()); + } + +} diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/iml/varioustests/VariousTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/iml/varioustests/VariousTest.java deleted file mode 100644 index cdfed8e494..0000000000 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/iml/varioustests/VariousTest.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * 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.restconf.iml.varioustests; - -import org.junit.Ignore; -import org.junit.Test; -import org.opendaylight.controller.sal.rest.impl.XmlToCompositeNodeProvider; -import org.opendaylight.controller.sal.restconf.impl.test.TestUtils; -import org.opendaylight.yangtools.yang.data.api.CompositeNode; -import org.w3c.dom.Document; - - -public class VariousTest { - - @Ignore - @Test - public void test() { - String[] split = "/something:dfsa/s:sda".split("/"); - System.out.println(split.length); - for (String str : split) { - System.out.println(">"+str+"<"); - } - - } - - @Test - public void loadXml() { - TestUtils.readInputToCnSn("/varioustest/xmldata.xml", XmlToCompositeNodeProvider.INSTANCE); -// TestUtils.normalizeCompositeNode(compositeNode, modules, schemaNodePath) - } - - @Test - public void buildXml() { -// Document doc; -// doc.createElementNS(namespaceURI, qualifiedName) - } - - -} diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnToJsonNotExistingLeafTypeTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnToJsonNotExistingLeafTypeTest.java index 17d7fe6be0..dd1502ba79 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnToJsonNotExistingLeafTypeTest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnToJsonNotExistingLeafTypeTest.java @@ -12,12 +12,10 @@ import static org.junit.Assert.assertTrue; import java.io.IOException; import java.util.Collections; -import java.util.Set; import javax.ws.rs.WebApplicationException; import org.junit.BeforeClass; -import org.junit.Ignore; import org.junit.Test; import org.opendaylight.controller.sal.rest.impl.StructuredDataToJsonProvider; import org.opendaylight.controller.sal.restconf.impl.test.DummyType; @@ -29,7 +27,6 @@ import org.opendaylight.yangtools.yang.data.api.MutableCompositeNode; import org.opendaylight.yangtools.yang.data.api.MutableSimpleNode; import org.opendaylight.yangtools.yang.data.impl.NodeFactory; import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; -import org.opendaylight.yangtools.yang.model.api.Module; import org.opendaylight.yangtools.yang.parser.builder.impl.ContainerSchemaNodeBuilder; import org.opendaylight.yangtools.yang.parser.builder.impl.LeafSchemaNodeBuilder; import org.slf4j.Logger; @@ -49,7 +46,7 @@ public class CnSnToJsonNotExistingLeafTypeTest extends YangAndXmlAndDataSchemaLo String jsonOutput = null; jsonOutput = TestUtils .writeCompNodeWithSchemaContextToOutput(prepareCompositeNode(), - (Set) Collections.EMPTY_SET, prepareDataSchemaNode(), + Collections.EMPTY_SET, prepareDataSchemaNode(), StructuredDataToJsonProvider.INSTANCE); assertNotNull(jsonOutput); assertTrue(jsonOutput.contains("\"lf1\": \"\"")); diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/xml/test/CnSnToXmlNotExistingLeafTypeTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/xml/test/CnSnToXmlNotExistingLeafTypeTest.java index 4218a69d3b..f81c1d63f5 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/xml/test/CnSnToXmlNotExistingLeafTypeTest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/xml/test/CnSnToXmlNotExistingLeafTypeTest.java @@ -7,12 +7,10 @@ */ package org.opendaylight.controller.sal.restconf.impl.cnsn.to.xml.test; -import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import java.io.IOException; import java.util.Collections; -import java.util.Set; import javax.ws.rs.WebApplicationException; @@ -21,10 +19,12 @@ import org.junit.Test; import org.opendaylight.controller.sal.rest.impl.StructuredDataToXmlProvider; import org.opendaylight.controller.sal.restconf.impl.test.DummyType; import org.opendaylight.controller.sal.restconf.impl.test.TestUtils; -import org.opendaylight.yangtools.yang.data.api.*; +import org.opendaylight.yangtools.yang.data.api.CompositeNode; +import org.opendaylight.yangtools.yang.data.api.ModifyAction; +import org.opendaylight.yangtools.yang.data.api.MutableCompositeNode; +import org.opendaylight.yangtools.yang.data.api.MutableSimpleNode; import org.opendaylight.yangtools.yang.data.impl.NodeFactory; import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; -import org.opendaylight.yangtools.yang.model.api.Module; import org.opendaylight.yangtools.yang.parser.builder.impl.ContainerSchemaNodeBuilder; import org.opendaylight.yangtools.yang.parser.builder.impl.LeafSchemaNodeBuilder; import org.slf4j.Logger; @@ -41,7 +41,7 @@ public class CnSnToXmlNotExistingLeafTypeTest { boolean nullPointerExceptionRaised = false; try { TestUtils.writeCompNodeWithSchemaContextToOutput(prepareCompositeNode(), - (Set) Collections.EMPTY_SET, prepareDataSchemaNode(), StructuredDataToXmlProvider.INSTANCE); + Collections.EMPTY_SET, prepareDataSchemaNode(), StructuredDataToXmlProvider.INSTANCE); } catch (WebApplicationException | IOException e) { LOG.error("WebApplicationException or IOException was raised"); } catch (NullPointerException e) { diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestGetOperationTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestGetOperationTest.java index be7be9444c..1e01020e78 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestGetOperationTest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestGetOperationTest.java @@ -8,6 +8,7 @@ package org.opendaylight.controller.sal.restconf.impl.test; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -19,9 +20,12 @@ import java.net.URI; import java.net.URISyntaxException; import java.util.ArrayList; import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import javax.ws.rs.core.Application; import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; import org.glassfish.jersey.server.ResourceConfig; import org.glassfish.jersey.test.JerseyTest; @@ -51,6 +55,9 @@ public class RestGetOperationTest extends JerseyTest { private static SchemaContext schemaContextTestModule; private static CompositeNode answerFromGet; + private static SchemaContext schemaContextModules; + private static SchemaContext schemaContextBehindMountPoint; + @BeforeClass public static void init() throws FileNotFoundException { schemaContextYangsIetf = TestUtils.loadSchemaContext("/full-versions/yangs"); @@ -62,15 +69,18 @@ public class RestGetOperationTest extends JerseyTest { restconfImpl.setBroker(brokerFacade); restconfImpl.setControllerContext(controllerContext); answerFromGet = prepareCompositeNodeWithIetfInterfacesInterfacesData(); + + schemaContextModules = TestUtils.loadSchemaContext("/modules"); + schemaContextBehindMountPoint = TestUtils.loadSchemaContext("/modules/modules-behind-mount-point"); } @Override protected Application configure() { /* enable/disable Jersey logs to console */ -// enable(TestProperties.LOG_TRAFFIC); -// enable(TestProperties.DUMP_ENTITY); -// enable(TestProperties.RECORD_LOG_LEVEL); -// set(TestProperties.RECORD_LOG_LEVEL, Level.ALL.intValue()); + // enable(TestProperties.LOG_TRAFFIC); + // enable(TestProperties.DUMP_ENTITY); + // enable(TestProperties.RECORD_LOG_LEVEL); + // set(TestProperties.RECORD_LOG_LEVEL, Level.ALL.intValue()); ResourceConfig resourceConfig = new ResourceConfig(); resourceConfig = resourceConfig.registerInstances(restconfImpl, StructuredDataToXmlProvider.INSTANCE, StructuredDataToJsonProvider.INSTANCE, XmlToCompositeNodeProvider.INSTANCE, @@ -118,7 +128,7 @@ public class RestGetOperationTest extends JerseyTest { when(mockMountService.getMountPoint(any(InstanceIdentifier.class))).thenReturn(mountInstance); ControllerContext.getInstance().setMountService(mockMountService); - + String uri = createUri("/config/", "ietf-interfaces:interfaces/interface/0/yang-ext:mount/test-module:cont/cont1"); assertEquals(200, get(uri, MediaType.APPLICATION_XML)); @@ -129,7 +139,8 @@ public class RestGetOperationTest extends JerseyTest { @Test public void getDataMountPointIntoHighestElement() throws UnsupportedEncodingException, URISyntaxException { - when(brokerFacade.readConfigurationDataBehindMountPoint(any(MountInstance.class), + when( + brokerFacade.readConfigurationDataBehindMountPoint(any(MountInstance.class), any(InstanceIdentifier.class))).thenReturn(prepareCnDataForMountPointTest()); MountInstance mountInstance = mock(MountInstance.class); when(mountInstance.getSchemaContext()).thenReturn(schemaContextTestModule); @@ -138,11 +149,342 @@ public class RestGetOperationTest extends JerseyTest { ControllerContext.getInstance().setMountService(mockMountService); - String uri = createUri("/config/", - "ietf-interfaces:interfaces/interface/0/yang-ext:mount/"); + String uri = createUri("/config/", "ietf-interfaces:interfaces/interface/0/yang-ext:mount/"); assertEquals(200, get(uri, MediaType.APPLICATION_XML)); } + // /modules + @Test + public void getModulesTest() throws UnsupportedEncodingException, FileNotFoundException { + ControllerContext.getInstance().setGlobalSchema(schemaContextModules); + + String uri = createUri("/modules", ""); + + Response response = target(uri).request("application/yang.api+json").get(); + validateModulesResponseJson(response); + + response = target(uri).request("application/yang.api+xml").get(); + validateModulesResponseXml(response); + } + + // /modules/module + @Test + public void getModuleTest() throws FileNotFoundException, UnsupportedEncodingException { + ControllerContext.getInstance().setGlobalSchema(schemaContextModules); + + String uri = createUri("/modules/module/module2/2014-01-02", ""); + + Response response = target(uri).request("application/yang.api+xml").get(); + assertEquals(200, response.getStatus()); + String responseBody = response.readEntity(String.class); + assertTrue("Module2 in xml wasn't found", prepareXmlRegex("module2", "2014-01-02", "module:2", responseBody) + .find()); + String[] split = responseBody.split(""); + + regex.append(".*<"); + regex.append(".*" + rpcName); + regex.append(".*" + namespace); + regex.append(".*/"); + regex.append(".*>"); + + regex.append(".*"); + + regex.append(".*"); + regex.append("$"); + Pattern ptrn = Pattern.compile(regex.toString(), Pattern.DOTALL); + return ptrn.matcher(searchIn); + } + + // /restconf/modules/pathToMountPoint/yang-ext:mount + @Test + public void getModulesBehindMountPoint() throws FileNotFoundException, UnsupportedEncodingException { + ControllerContext controllerContext = ControllerContext.getInstance(); + controllerContext.setGlobalSchema(schemaContextModules); + + MountInstance mountInstance = mock(MountInstance.class); + when(mountInstance.getSchemaContext()).thenReturn(schemaContextBehindMountPoint); + MountService mockMountService = mock(MountService.class); + when(mockMountService.getMountPoint(any(InstanceIdentifier.class))).thenReturn(mountInstance); + + controllerContext.setMountService(mockMountService); + + String uri = createUri("/modules/", "ietf-interfaces:interfaces/interface/0/yang-ext:mount/"); + + Response response = target(uri).request("application/yang.api+json").get(); + assertEquals(200, response.getStatus()); + String responseBody = response.readEntity(String.class); + + assertTrue( + "module1-behind-mount-point in json wasn't found", + prepareJsonRegex("module1-behind-mount-point", "2014-02-03", "module:1:behind:mount:point", + responseBody).find()); + assertTrue( + "module2-behind-mount-point in json wasn't found", + prepareJsonRegex("module2-behind-mount-point", "2014-02-04", "module:2:behind:mount:point", + responseBody).find()); + + response = target(uri).request("application/yang.api+xml").get(); + assertEquals(200, response.getStatus()); + responseBody = response.readEntity(String.class); + assertTrue( + "module1-behind-mount-point in json wasn't found", + prepareXmlRegex("module1-behind-mount-point", "2014-02-03", "module:1:behind:mount:point", responseBody) + .find()); + assertTrue( + "module2-behind-mount-point in json wasn't found", + prepareXmlRegex("module2-behind-mount-point", "2014-02-04", "module:2:behind:mount:point", responseBody) + .find()); + + } + + // /restconf/modules/module/pathToMountPoint/yang-ext:mount/moduleName/revision + @Test + public void getModuleBehindMountPoint() throws FileNotFoundException, UnsupportedEncodingException { + ControllerContext controllerContext = ControllerContext.getInstance(); + controllerContext.setGlobalSchema(schemaContextModules); + + MountInstance mountInstance = mock(MountInstance.class); + when(mountInstance.getSchemaContext()).thenReturn(schemaContextBehindMountPoint); + MountService mockMountService = mock(MountService.class); + when(mockMountService.getMountPoint(any(InstanceIdentifier.class))).thenReturn(mountInstance); + + controllerContext.setMountService(mockMountService); + + String uri = createUri("/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()); + String responseBody = response.readEntity(String.class); + + assertTrue( + "module1-behind-mount-point in json wasn't found", + prepareJsonRegex("module1-behind-mount-point", "2014-02-03", "module:1:behind:mount:point", + responseBody).find()); + String[] split = responseBody.split("\"module\""); + assertEquals("\"module\" element is returned more then once",2,split.length); + + + response = target(uri).request("application/yang.api+xml").get(); + assertEquals(200, response.getStatus()); + responseBody = response.readEntity(String.class); + assertTrue( + "module1-behind-mount-point in json wasn't found", + prepareXmlRegex("module1-behind-mount-point", "2014-02-03", "module:1:behind:mount:point", responseBody) + .find()); + split = responseBody.split(""); + + regex.append(".*"); + regex.append(".*" + module); + regex.append(".*<\\/name>"); + + regex.append(".*"); + regex.append(".*" + revision); + regex.append(".*<\\/revision>"); + + regex.append(".*"); + regex.append(".*" + namespace); + regex.append(".*<\\/namespace>"); + + regex.append(".*<\\/module.*>"); + + regex.append(".*"); + regex.append("$"); + + Pattern ptrn = Pattern.compile(regex.toString(), Pattern.DOTALL); + return ptrn.matcher(searchIn); + } + + private void prepareMockForModulesTest(ControllerContext mockedControllerContext) throws FileNotFoundException { + SchemaContext schemaContext = TestUtils.loadSchemaContext("/modules"); + mockedControllerContext.setGlobalSchema(schemaContext); + // when(mockedControllerContext.getGlobalSchema()).thenReturn(schemaContext); + } + private int get(String uri, String mediaType) { return target(uri).request(mediaType).get().getStatus(); } diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestOperationUtils.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestOperationUtils.java index 3175ba9821..a0e61a6fa1 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestOperationUtils.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestOperationUtils.java @@ -15,13 +15,13 @@ import com.google.common.base.Charsets; public class RestOperationUtils { - static final String JSON = "+json"; - static final String XML = "+xml"; + public static final String JSON = "+json"; + public static final String XML = "+xml"; private RestOperationUtils() { } - static String createUri(String prefix, String encodedPart) throws UnsupportedEncodingException { + public static String createUri(String prefix, String encodedPart) throws UnsupportedEncodingException { return URI.create(prefix + URLEncoder.encode(encodedPart, Charsets.US_ASCII.name()).toString()).toASCIIString(); } } diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/websockets/client/IClientMessageCallback.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/websockets/client/IClientMessageCallback.java new file mode 100644 index 0000000000..63b8e6b4b7 --- /dev/null +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/websockets/client/IClientMessageCallback.java @@ -0,0 +1,9 @@ +package org.opendaylight.controller.sal.restconf.impl.websockets.client; + +/** + * Created by mbobak on 1/22/14. + */ +public interface IClientMessageCallback { + + public void onMessageReceived(Object message); +} diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/websockets/client/WebSocketClient.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/websockets/client/WebSocketClient.java new file mode 100644 index 0000000000..845d54ea1f --- /dev/null +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/websockets/client/WebSocketClient.java @@ -0,0 +1,130 @@ +/* + * 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.restconf.impl.websockets.client; + +import io.netty.bootstrap.Bootstrap; +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import io.netty.channel.ChannelInitializer; +import io.netty.channel.ChannelPipeline; +import io.netty.channel.EventLoopGroup; +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.channel.socket.SocketChannel; +import io.netty.channel.socket.nio.NioSocketChannel; +import io.netty.handler.codec.http.HttpClientCodec; +import io.netty.handler.codec.http.HttpObjectAggregator; +import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame; +import io.netty.handler.codec.http.websocketx.PingWebSocketFrame; +import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; +import io.netty.handler.codec.http.websocketx.WebSocketClientHandshakerFactory; +import io.netty.handler.codec.http.websocketx.WebSocketVersion; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.net.URI; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class WebSocketClient { + + private final URI uri; + private Bootstrap bootstrap = new Bootstrap();; + private final WebSocketClientHandler clientHandler; + private static final Logger logger = LoggerFactory.getLogger(WebSocketClient.class); + private Channel clientChannel; + private final EventLoopGroup group = new NioEventLoopGroup(); + + public WebSocketClient(URI uri,IClientMessageCallback clientMessageCallback) { + this.uri = uri; + clientHandler = new WebSocketClientHandler( + WebSocketClientHandshakerFactory.newHandshaker( + uri, WebSocketVersion.V13, null, false,null),clientMessageCallback); // last null could be replaced with DefaultHttpHeaders + initialize(); + } + private void initialize(){ + + String protocol = uri.getScheme(); + if (!"http".equals(protocol)) { + throw new IllegalArgumentException("Unsupported protocol: " + protocol); + } + + bootstrap.group(group) + .channel(NioSocketChannel.class) + .handler(new ChannelInitializer() { + @Override + public void initChannel(SocketChannel ch) throws Exception { + ChannelPipeline pipeline = ch.pipeline(); + pipeline.addLast("http-codec", new HttpClientCodec()); + pipeline.addLast("aggregator", new HttpObjectAggregator(8192)); + pipeline.addLast("ws-handler", clientHandler); + } + }); + } + public void connect() throws InterruptedException{ + System.out.println("WebSocket Client connecting"); + clientChannel = bootstrap.connect(uri.getHost(), uri.getPort()).sync().channel(); + clientHandler.handshakeFuture().sync(); + } + + public void writeAndFlush(String message){ + clientChannel.writeAndFlush(new TextWebSocketFrame(message)); + } + public void writeAndFlush(Object message){ + clientChannel.writeAndFlush(message); + } + + public void ping(){ + clientChannel.writeAndFlush(new PingWebSocketFrame(Unpooled.copiedBuffer(new byte[]{1, 2, 3, 4, 5, 6}))); + } + + public void close(String reasonText) throws InterruptedException { + CloseWebSocketFrame closeWebSocketFrame = new CloseWebSocketFrame(1000,reasonText); + clientChannel.writeAndFlush(closeWebSocketFrame); + + // WebSocketClientHandler will close the connection when the server + // responds to the CloseWebSocketFrame. + clientChannel.closeFuture().sync(); + group.shutdownGracefully(); + } + + public static void main(String[] args) throws Exception { + URI uri; + if (args.length > 0) { + uri = new URI(args[0]); + } else { + uri = new URI("http://192.168.1.101:8181/opendaylight-inventory:nodes"); + } + IClientMessageCallback messageCallback = new ClientMessageCallback(); + WebSocketClient webSocketClient = new WebSocketClient(uri, messageCallback); + webSocketClient.connect(); + + while (true) { + BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); + String input = br.readLine(); + if (input.equals("q")) { + System.out.print("Would you like to close stream? (Y = yes, empty = yes)\n"); + input = br.readLine(); + if (input.equals("yes") || input.isEmpty()) { + webSocketClient.close("opendaylight-inventory:nodes"); + break; + } + } + } + } + + private static class ClientMessageCallback implements IClientMessageCallback { + @Override + public void onMessageReceived(Object message) { + if (message instanceof TextWebSocketFrame) { + logger.info("received message {}"+ ((TextWebSocketFrame)message).text()); + } + } + } + +} diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/websockets/client/WebSocketClientHandler.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/websockets/client/WebSocketClientHandler.java new file mode 100644 index 0000000000..0a16e254cc --- /dev/null +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/websockets/client/WebSocketClientHandler.java @@ -0,0 +1,95 @@ +/* + * 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.restconf.impl.websockets.client; + +import io.netty.channel.Channel; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelPromise; +import io.netty.channel.SimpleChannelInboundHandler; +import io.netty.handler.codec.http.FullHttpResponse; +import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame; +import io.netty.handler.codec.http.websocketx.PongWebSocketFrame; +import io.netty.handler.codec.http.websocketx.WebSocketClientHandshaker; +import io.netty.handler.codec.http.websocketx.WebSocketFrame; +import io.netty.util.CharsetUtil; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class WebSocketClientHandler extends SimpleChannelInboundHandler { + + private static final Logger logger = LoggerFactory.getLogger(WebSocketClientHandler.class.toString()); + private final WebSocketClientHandshaker handshaker; + private ChannelPromise handshakeFuture; + private final IClientMessageCallback messageListener; + + + public WebSocketClientHandler(WebSocketClientHandshaker handshaker,IClientMessageCallback listener) { + this.handshaker = handshaker; + this.messageListener = listener; + } + + public ChannelFuture handshakeFuture() { + return handshakeFuture; + } + + @Override + public void handlerAdded(ChannelHandlerContext ctx) throws Exception { + handshakeFuture = ctx.newPromise(); + } + + @Override + public void channelActive(ChannelHandlerContext ctx) throws Exception { + handshaker.handshake(ctx.channel()); + } + + @Override + public void channelInactive(ChannelHandlerContext ctx) throws Exception { + logger.info("WebSocket Client disconnected!"); + } + + @Override + public void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception { + Channel ch = ctx.channel(); + if (!handshaker.isHandshakeComplete()) { + handshaker.finishHandshake(ch, (FullHttpResponse) msg); + logger.info("WebSocket Client connected!"); + handshakeFuture.setSuccess(); + return; + } + + if (msg instanceof FullHttpResponse) { + FullHttpResponse response = (FullHttpResponse) msg; + throw new Exception("Unexpected FullHttpResponse (getStatus=" + response.getStatus() + ", content=" + + response.content().toString(CharsetUtil.UTF_8) + ')'); + } + + messageListener.onMessageReceived(msg); + WebSocketFrame frame = (WebSocketFrame) msg; + + if (frame instanceof PongWebSocketFrame) { + logger.info("WebSocket Client received pong"); + } else if (frame instanceof CloseWebSocketFrame) { + logger.info("WebSocket Client received closing"); + ch.close(); + } + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { + cause.printStackTrace(); + + if (!handshakeFuture.isDone()) { + handshakeFuture.setFailure(cause); + } + + ctx.close(); + } +} + diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/websockets/test/RestStream.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/websockets/test/RestStream.java new file mode 100644 index 0000000000..4dcc63e89a --- /dev/null +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/websockets/test/RestStream.java @@ -0,0 +1,101 @@ +/* + * 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.restconf.impl.websockets.test; + +import static org.junit.Assert.assertEquals; +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; +import java.net.URI; + +import javax.ws.rs.client.Entity; +import javax.ws.rs.core.Application; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +import org.glassfish.jersey.server.ResourceConfig; +import org.glassfish.jersey.test.JerseyTest; +import org.junit.BeforeClass; +import org.junit.Test; +import org.opendaylight.controller.sal.rest.impl.JsonToCompositeNodeProvider; +import org.opendaylight.controller.sal.rest.impl.StructuredDataToJsonProvider; +import org.opendaylight.controller.sal.rest.impl.StructuredDataToXmlProvider; +import org.opendaylight.controller.sal.rest.impl.XmlToCompositeNodeProvider; +import org.opendaylight.controller.sal.restconf.impl.BrokerFacade; +import org.opendaylight.controller.sal.restconf.impl.ControllerContext; +import org.opendaylight.controller.sal.restconf.impl.RestconfImpl; +import org.opendaylight.controller.sal.restconf.impl.test.TestUtils; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; + +public class RestStream extends JerseyTest { + + private static BrokerFacade brokerFacade; + private static RestconfImpl restconfImpl; + private static SchemaContext schemaContextYangsIetf; + + @BeforeClass + public static void init() throws FileNotFoundException { + schemaContextYangsIetf = TestUtils.loadSchemaContext("/full-versions/yangs"); + ControllerContext controllerContext = ControllerContext.getInstance(); + controllerContext.setSchemas(schemaContextYangsIetf); + brokerFacade = mock(BrokerFacade.class); + restconfImpl = RestconfImpl.getInstance(); + restconfImpl.setBroker(brokerFacade); + restconfImpl.setControllerContext(controllerContext); + } + + @Override + protected Application configure() { + /* enable/disable Jersey logs to console */ +// enable(TestProperties.LOG_TRAFFIC); +// enable(TestProperties.DUMP_ENTITY); +// enable(TestProperties.RECORD_LOG_LEVEL); +// set(TestProperties.RECORD_LOG_LEVEL, Level.ALL.intValue()); + ResourceConfig resourceConfig = new ResourceConfig(); + resourceConfig = resourceConfig.registerInstances(restconfImpl, StructuredDataToXmlProvider.INSTANCE, + StructuredDataToJsonProvider.INSTANCE, XmlToCompositeNodeProvider.INSTANCE, + JsonToCompositeNodeProvider.INSTANCE); + return resourceConfig; + } + + @Test + public void testCallRpcCallGet() throws UnsupportedEncodingException, InterruptedException { + String uri = createUri("/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("ietf-interfaces:interfaces/ietf-interfaces:interface/eth0")); + + uri = createUri("/streams/stream/", "ietf-interfaces:interfaces/ietf-interfaces:interface/eth0"); + Response responseWithRedirectionUri = get(uri, MediaType.APPLICATION_XML); + final URI websocketServerUri = responseWithRedirectionUri.getLocation(); + assertNotNull(websocketServerUri); + assertEquals(websocketServerUri.toString(), "http://localhost:8181/ietf-interfaces:interfaces/ietf-interfaces:interface/eth0"); + } + + private Response post(String uri, String mediaType, String data) { + return target(uri).request(mediaType).post(Entity.entity(data, mediaType)); + } + + private Response get(String uri, String mediaType) { + return target(uri).request(mediaType).get(); + } + + private String getRpcInput() { + StringBuilder sb = new StringBuilder(); + sb.append(""); + sb.append("/int:interfaces/int:interface[int:name='eth0']"); + sb.append(""); + return sb.toString(); + } + +} diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/full-versions/yangs/sal-remote@2014-01-14.yang b/opendaylight/md-sal/sal-rest-connector/src/test/resources/full-versions/yangs/sal-remote@2014-01-14.yang new file mode 100644 index 0000000000..d12e252711 --- /dev/null +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/full-versions/yangs/sal-remote@2014-01-14.yang @@ -0,0 +1,98 @@ +module sal-remote { + + yang-version 1; + namespace "urn:opendaylight:params:xml:ns:yang:controller:md:sal:remote"; + prefix "sal-remote"; + + + organization "Cisco Systems, Inc."; + contact "Martin Bobak "; + + description + "This module contains the definition of methods related to + sal remote model. + + Copyright (c)2013 Cisco Systems, Inc. All rights reserved. + + This program and the accompanying materials are made available + under the terms of the Eclipse Public License v1.0 which + accompanies this distribution, and is available at + http://www.eclipse.org/legal/epl-v10.html"; + + revision "2014-01-14" { + description + "Initial revision"; + } + + + typedef q-name { + type string; + reference + "http://www.w3.org/TR/2004/REC-xmlschema-2-20041028/#QName"; + } + + rpc create-data-change-event-subscription { + input { + leaf path { + type instance-identifier; + description "Subtree path. "; + } + } + output { + leaf stream-name { + type string; + description "Notification stream name."; + } + } + } + + notification data-changed-notification { + description "Data change notification."; + list data-change-event { + key path; + leaf path { + type instance-identifier; + } + leaf store { + type enumeration { + enum config; + enum operation; + } + } + leaf operation { + type enumeration { + enum created; + enum updated; + enum deleted; + } + } + anyxml data{ + description "DataObject "; + } + } + } + + rpc create-notification-stream { + input { + leaf-list notifications { + type q-name; + description "Notification QNames"; + } + } + output { + leaf notification-stream-identifier { + type string; + description "Unique notification stream identifier, in which notifications will be propagated"; + } + } + } + + rpc begin-transaction{ + output{ + anyxml data-modification-transaction{ + description "DataModificationTransaction xml"; + } + } + } + +} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/modules/iana-if-type.yang b/opendaylight/md-sal/sal-rest-connector/src/test/resources/modules/iana-if-type.yang new file mode 100644 index 0000000000..7bd0003b5d --- /dev/null +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/modules/iana-if-type.yang @@ -0,0 +1,1517 @@ +module iana-if-type { + namespace "urn:ietf:params:xml:ns:yang:iana-if-type"; + prefix ianaift; + + organization "IANA"; + contact + " Internet Assigned Numbers Authority + + Postal: ICANN + 4676 Admiralty Way, Suite 330 + Marina del Rey, CA 90292 + + Tel: +1 310 823 9358 + E-Mail: iana&iana.org"; + description + "This YANG module defines the iana-if-type typedef, which + contains YANG definitions for IANA-registered interface types. + + This YANG module is maintained by IANA, and reflects the + 'ifType definitions' registry. + + The latest revision of this YANG module can be obtained from + the IANA web site. + + Copyright (c) 2011 IETF Trust and the persons identified as + authors of the code. All rights reserved. + + Redistribution and use in source and binary forms, with or + without modification, is permitted pursuant to, and subject + to the license terms contained in, the Simplified BSD License + set forth in Section 4.c of the IETF Trust's Legal Provisions + Relating to IETF Documents + (http://trustee.ietf.org/license-info). + + This version of this YANG module is part of RFC XXXX; see + the RFC itself for full legal notices."; + // RFC Ed.: replace XXXX with actual RFC number and remove this + // note. + + // RFC Ed.: update the date below with the date of RFC publication + // and remove this note. + revision 2013-07-04 { + description + "Initial revision."; + reference + "RFC XXXX: IANA Interface Type YANG Module"; + } + + typedef iana-if-type { + type enumeration { + enum "other" { + value 1; + description + "None of the following"; + } + enum "regular1822" { + value 2; + } + enum "hdh1822" { + value 3; + } + enum "ddnX25" { + value 4; + } + enum "rfc877x25" { + value 5; + reference + "RFC 1382 - SNMP MIB Extension for the X.25 Packet Layer"; + } + enum "ethernetCsmacd" { + value 6; + description + "For all ethernet-like interfaces, regardless of speed, + as per RFC3635."; + reference + "RFC 3635 - Definitions of Managed Objects for the + Ethernet-like Interface Types."; + } + enum "iso88023Csmacd" { + value 7; + status deprecated; + description + "Deprecated via RFC3635. + Use ethernetCsmacd(6) instead."; + reference + "RFC 3635 - Definitions of Managed Objects for the + Ethernet-like Interface Types."; + } + enum "iso88024TokenBus" { + value 8; + } + enum "iso88025TokenRing" { + value 9; + } + enum "iso88026Man" { + value 10; + } + enum "starLan" { + value 11; + status deprecated; + description + "Deprecated via RFC3635. + Use ethernetCsmacd(6) instead."; + reference + "RFC 3635 - Definitions of Managed Objects for the + Ethernet-like Interface Types."; + } + enum "proteon10Mbit" { + value 12; + } + enum "proteon80Mbit" { + value 13; + } + enum "hyperchannel" { + value 14; + } + enum "fddi" { + value 15; + reference + "RFC 1512 - FDDI Management Information Base"; + } + enum "lapb" { + value 16; + reference + "RFC 1381 - SNMP MIB Extension for X.25 LAPB"; + } + enum "sdlc" { + value 17; + } + enum "ds1" { + value 18; + description + "DS1-MIB"; + reference + "RFC 4805 - Definitions of Managed Objects for the + DS1, J1, E1, DS2, and E2 Interface Types"; + } + enum "e1" { + value 19; + status obsolete; + description + "Obsolete see DS1-MIB"; + reference + "RFC 4805 - Definitions of Managed Objects for the + DS1, J1, E1, DS2, and E2 Interface Types"; + } + enum "basicISDN" { + value 20; + description + "see also RFC2127"; + } + enum "primaryISDN" { + value 21; + } + enum "propPointToPointSerial" { + value 22; + description + "proprietary serial"; + } + enum "ppp" { + value 23; + } + enum "softwareLoopback" { + value 24; + } + enum "eon" { + value 25; + description + "CLNP over IP"; + } + enum "ethernet3Mbit" { + value 26; + } + enum "nsip" { + value 27; + description + "XNS over IP"; + } + enum "slip" { + value 28; + description + "generic SLIP"; + } + enum "ultra" { + value 29; + description + "ULTRA technologies"; + } + enum "ds3" { + value 30; + description + "DS3-MIB"; + reference + "RFC 3896 - Definitions of Managed Objects for the + DS3/E3 Interface Type"; + } + enum "sip" { + value 31; + description + "SMDS, coffee"; + reference + "RFC 1694 - Definitions of Managed Objects for SMDS + Interfaces using SMIv2"; + } + enum "frameRelay" { + value 32; + description + "DTE only."; + reference + "RFC 2115 - Management Information Base for Frame Relay + DTEs Using SMIv2"; + } + enum "rs232" { + value 33; + reference + "RFC 1659 - Definitions of Managed Objects for RS-232-like + Hardware Devices using SMIv2"; + } + enum "para" { + value 34; + description + "parallel-port"; + reference + "RFC 1660 - Definitions of Managed Objects for + Parallel-printer-like Hardware Devices using + SMIv2"; + } + enum "arcnet" { + value 35; + description + "arcnet"; + } + enum "arcnetPlus" { + value 36; + description + "arcnet plus"; + } + enum "atm" { + value 37; + description + "ATM cells"; + } + enum "miox25" { + value 38; + reference + "RFC 1461 - SNMP MIB extension for Multiprotocol + Interconnect over X.25"; + } + enum "sonet" { + value 39; + description + "SONET or SDH"; + } + enum "x25ple" { + value 40; + reference + "RFC 2127 - ISDN Management Information Base using SMIv2"; + } + enum "iso88022llc" { + value 41; + } + enum "localTalk" { + value 42; + } + enum "smdsDxi" { + value 43; + } + enum "frameRelayService" { + value 44; + description + "FRNETSERV-MIB"; + reference + "RFC 2954 - Definitions of Managed Objects for Frame + Relay Service"; + } + enum "v35" { + value 45; + } + enum "hssi" { + value 46; + } + enum "hippi" { + value 47; + } + enum "modem" { + value 48; + description + "Generic modem"; + } + enum "aal5" { + value 49; + description + "AAL5 over ATM"; + } + enum "sonetPath" { + value 50; + } + enum "sonetVT" { + value 51; + } + enum "smdsIcip" { + value 52; + description + "SMDS InterCarrier Interface"; + } + enum "propVirtual" { + value 53; + description + "proprietary virtual/internal"; + reference + "RFC 2863 - The Interfaces Group MIB"; + } + enum "propMultiplexor" { + value 54; + description + "proprietary multiplexing"; + reference + "RFC 2863 - The Interfaces Group MIB"; + } + enum "ieee80212" { + value 55; + description + "100BaseVG"; + } + enum "fibreChannel" { + value 56; + description + "Fibre Channel"; + } + enum "hippiInterface" { + value 57; + description + "HIPPI interfaces"; + } + enum "frameRelayInterconnect" { + value 58; + status obsolete; + description + "Obsolete use either + frameRelay(32) or frameRelayService(44)."; + } + enum "aflane8023" { + value 59; + description + "ATM Emulated LAN for 802.3"; + } + enum "aflane8025" { + value 60; + description + "ATM Emulated LAN for 802.5"; + } + enum "cctEmul" { + value 61; + description + "ATM Emulated circuit"; + } + enum "fastEther" { + value 62; + status deprecated; + description + "Obsoleted via RFC3635. + ethernetCsmacd(6) should be used instead"; + reference + "RFC 3635 - Definitions of Managed Objects for the + Ethernet-like Interface Types."; + } + enum "isdn" { + value 63; + description + "ISDN and X.25"; + reference + "RFC 1356 - Multiprotocol Interconnect on X.25 and ISDN + in the Packet Mode"; + } + enum "v11" { + value 64; + description + "CCITT V.11/X.21"; + } + enum "v36" { + value 65; + description + "CCITT V.36"; + } + enum "g703at64k" { + value 66; + description + "CCITT G703 at 64Kbps"; + } + enum "g703at2mb" { + value 67; + status obsolete; + description + "Obsolete see DS1-MIB"; + } + enum "qllc" { + value 68; + description + "SNA QLLC"; + } + enum "fastEtherFX" { + value 69; + status deprecated; + description + "Obsoleted via RFC3635 + ethernetCsmacd(6) should be used instead"; + reference + "RFC 3635 - Definitions of Managed Objects for the + Ethernet-like Interface Types."; + } + enum "channel" { + value 70; + description + "channel"; + } + enum "ieee80211" { + value 71; + description + "radio spread spectrum"; + } + enum "ibm370parChan" { + value 72; + description + "IBM System 360/370 OEMI Channel"; + } + enum "escon" { + value 73; + description + "IBM Enterprise Systems Connection"; + } + enum "dlsw" { + value 74; + description + "Data Link Switching"; + } + enum "isdns" { + value 75; + description + "ISDN S/T interface"; + } + enum "isdnu" { + value 76; + description + "ISDN U interface"; + } + enum "lapd" { + value 77; + description + "Link Access Protocol D"; + } + enum "ipSwitch" { + value 78; + description + "IP Switching Objects"; + } + enum "rsrb" { + value 79; + description + "Remote Source Route Bridging"; + } + enum "atmLogical" { + value 80; + description + "ATM Logical Port"; + reference + "RFC 3606 - Definitions of Supplemental Managed Objects + for ATM Interface"; + } + enum "ds0" { + value 81; + description + "Digital Signal Level 0"; + reference + "RFC 2494 - Definitions of Managed Objects for the DS0 + and DS0 Bundle Interface Type"; + } + enum "ds0Bundle" { + value 82; + description + "group of ds0s on the same ds1"; + reference + "RFC 2494 - Definitions of Managed Objects for the DS0 + and DS0 Bundle Interface Type"; + } + enum "bsc" { + value 83; + description + "Bisynchronous Protocol"; + } + enum "async" { + value 84; + description + "Asynchronous Protocol"; + } + enum "cnr" { + value 85; + description + "Combat Net Radio"; + } + enum "iso88025Dtr" { + value 86; + description + "ISO 802.5r DTR"; + } + enum "eplrs" { + value 87; + description + "Ext Pos Loc Report Sys"; + } + enum "arap" { + value 88; + description + "Appletalk Remote Access Protocol"; + } + enum "propCnls" { + value 89; + description + "Proprietary Connectionless Protocol"; + } + enum "hostPad" { + value 90; + description + "CCITT-ITU X.29 PAD Protocol"; + } + enum "termPad" { + value 91; + description + "CCITT-ITU X.3 PAD Facility"; + } + enum "frameRelayMPI" { + value 92; + description + "Multiproto Interconnect over FR"; + } + enum "x213" { + value 93; + description + "CCITT-ITU X213"; + } + enum "adsl" { + value 94; + description + "Asymmetric Digital Subscriber Loop"; + } + enum "radsl" { + value 95; + description + "Rate-Adapt. Digital Subscriber Loop"; + } + enum "sdsl" { + value 96; + description + "Symmetric Digital Subscriber Loop"; + } + enum "vdsl" { + value 97; + description + "Very H-Speed Digital Subscrib. Loop"; + } + enum "iso88025CRFPInt" { + value 98; + description + "ISO 802.5 CRFP"; + } + enum "myrinet" { + value 99; + description + "Myricom Myrinet"; + } + enum "voiceEM" { + value 100; + description + "voice recEive and transMit"; + } + enum "voiceFXO" { + value 101; + description + "voice Foreign Exchange Office"; + } + enum "voiceFXS" { + value 102; + description + "voice Foreign Exchange Station"; + } + enum "voiceEncap" { + value 103; + description + "voice encapsulation"; + } + enum "voiceOverIp" { + value 104; + description + "voice over IP encapsulation"; + } + enum "atmDxi" { + value 105; + description + "ATM DXI"; + } + enum "atmFuni" { + value 106; + description + "ATM FUNI"; + } + enum "atmIma" { + value 107; + description + "ATM IMA"; + } + enum "pppMultilinkBundle" { + value 108; + description + "PPP Multilink Bundle"; + } + enum "ipOverCdlc" { + value 109; + description + "IBM ipOverCdlc"; + } + enum "ipOverClaw" { + value 110; + description + "IBM Common Link Access to Workstn"; + } + enum "stackToStack" { + value 111; + description + "IBM stackToStack"; + } + enum "virtualIpAddress" { + value 112; + description + "IBM VIPA"; + } + enum "mpc" { + value 113; + description + "IBM multi-protocol channel support"; + } + enum "ipOverAtm" { + value 114; + description + "IBM ipOverAtm"; + reference + "RFC 2320 - Definitions of Managed Objects for Classical IP + and ARP Over ATM Using SMIv2 (IPOA-MIB)"; + } + enum "iso88025Fiber" { + value 115; + description + "ISO 802.5j Fiber Token Ring"; + } + enum "tdlc" { + value 116; + description + "IBM twinaxial data link control"; + } + enum "gigabitEthernet" { + value 117; + status deprecated; + description + "Obsoleted via RFC3635 + ethernetCsmacd(6) should be used instead"; + reference + "RFC 3635 - Definitions of Managed Objects for the + Ethernet-like Interface Types."; + } + enum "hdlc" { + value 118; + description + "HDLC"; + } + enum "lapf" { + value 119; + description + "LAP F"; + } + enum "v37" { + value 120; + description + "V.37"; + } + enum "x25mlp" { + value 121; + description + "Multi-Link Protocol"; + } + enum "x25huntGroup" { + value 122; + description + "X25 Hunt Group"; + } + enum "transpHdlc" { + value 123; + description + "Transp HDLC"; + } + enum "interleave" { + value 124; + description + "Interleave channel"; + } + enum "fast" { + value 125; + description + "Fast channel"; + } + enum "ip" { + value 126; + description + "IP (for APPN HPR in IP networks)"; + } + enum "docsCableMaclayer" { + value 127; + description + "CATV Mac Layer"; + } + enum "docsCableDownstream" { + value 128; + description + "CATV Downstream interface"; + } + enum "docsCableUpstream" { + value 129; + description + "CATV Upstream interface"; + } + enum "a12MppSwitch" { + value 130; + description + "Avalon Parallel Processor"; + } + enum "tunnel" { + value 131; + description + "Encapsulation interface"; + } + enum "coffee" { + value 132; + description + "coffee pot"; + reference + "RFC 2325 - Coffee MIB"; + } + enum "ces" { + value 133; + description + "Circuit Emulation Service"; + } + enum "atmSubInterface" { + value 134; + description + "ATM Sub Interface"; + } + enum "l2vlan" { + value 135; + description + "Layer 2 Virtual LAN using 802.1Q"; + } + enum "l3ipvlan" { + value 136; + description + "Layer 3 Virtual LAN using IP"; + } + enum "l3ipxvlan" { + value 137; + description + "Layer 3 Virtual LAN using IPX"; + } + enum "digitalPowerline" { + value 138; + description + "IP over Power Lines"; + } + enum "mediaMailOverIp" { + value 139; + description + "Multimedia Mail over IP"; + } + enum "dtm" { + value 140; + description + "Dynamic syncronous Transfer Mode"; + } + enum "dcn" { + value 141; + description + "Data Communications Network"; + } + enum "ipForward" { + value 142; + description + "IP Forwarding Interface"; + } + enum "msdsl" { + value 143; + description + "Multi-rate Symmetric DSL"; + } + enum "ieee1394" { + value 144; + description + "IEEE1394 High Performance Serial Bus"; + } + enum "if-gsn" { + value 145; + description + "HIPPI-6400"; + } + enum "dvbRccMacLayer" { + value 146; + description + "DVB-RCC MAC Layer"; + } + enum "dvbRccDownstream" { + value 147; + description + "DVB-RCC Downstream Channel"; + } + enum "dvbRccUpstream" { + value 148; + description + "DVB-RCC Upstream Channel"; + } + enum "atmVirtual" { + value 149; + description + "ATM Virtual Interface"; + } + enum "mplsTunnel" { + value 150; + description + "MPLS Tunnel Virtual Interface"; + } + enum "srp" { + value 151; + description + "Spatial Reuse Protocol"; + } + enum "voiceOverAtm" { + value 152; + description + "Voice Over ATM"; + } + enum "voiceOverFrameRelay" { + value 153; + description + "Voice Over Frame Relay"; + } + enum "idsl" { + value 154; + description + "Digital Subscriber Loop over ISDN"; + } + enum "compositeLink" { + value 155; + description + "Avici Composite Link Interface"; + } + enum "ss7SigLink" { + value 156; + description + "SS7 Signaling Link"; + } + enum "propWirelessP2P" { + value 157; + description + "Prop. P2P wireless interface"; + } + enum "frForward" { + value 158; + description + "Frame Forward Interface"; + } + enum "rfc1483" { + value 159; + description + "Multiprotocol over ATM AAL5"; + reference + "RFC 1483 - Multiprotocol Encapsulation over ATM + Adaptation Layer 5"; + } + enum "usb" { + value 160; + description + "USB Interface"; + } + enum "ieee8023adLag" { + value 161; + description + "IEEE 802.3ad Link Aggregate"; + } + enum "bgppolicyaccounting" { + value 162; + description + "BGP Policy Accounting"; + } + enum "frf16MfrBundle" { + value 163; + description + "FRF .16 Multilink Frame Relay"; + } + enum "h323Gatekeeper" { + value 164; + description + "H323 Gatekeeper"; + } + enum "h323Proxy" { + value 165; + description + "H323 Voice and Video Proxy"; + } + enum "mpls" { + value 166; + description + "MPLS"; + } + enum "mfSigLink" { + value 167; + description + "Multi-frequency signaling link"; + } + enum "hdsl2" { + value 168; + description + "High Bit-Rate DSL - 2nd generation"; + } + enum "shdsl" { + value 169; + description + "Multirate HDSL2"; + } + enum "ds1FDL" { + value 170; + description + "Facility Data Link 4Kbps on a DS1"; + } + enum "pos" { + value 171; + description + "Packet over SONET/SDH Interface"; + } + enum "dvbAsiIn" { + value 172; + description + "DVB-ASI Input"; + } + enum "dvbAsiOut" { + value 173; + description + "DVB-ASI Output"; + } + enum "plc" { + value 174; + description + "Power Line Communtications"; + } + enum "nfas" { + value 175; + description + "Non Facility Associated Signaling"; + } + enum "tr008" { + value 176; + description + "TR008"; + } + enum "gr303RDT" { + value 177; + description + "Remote Digital Terminal"; + } + enum "gr303IDT" { + value 178; + description + "Integrated Digital Terminal"; + } + enum "isup" { + value 179; + description + "ISUP"; + } + enum "propDocsWirelessMaclayer" { + value 180; + description + "Cisco proprietary Maclayer"; + } + enum "propDocsWirelessDownstream" { + value 181; + description + "Cisco proprietary Downstream"; + } + enum "propDocsWirelessUpstream" { + value 182; + description + "Cisco proprietary Upstream"; + } + enum "hiperlan2" { + value 183; + description + "HIPERLAN Type 2 Radio Interface"; + } + enum "propBWAp2Mp" { + value 184; + description + "PropBroadbandWirelessAccesspt2multipt use of this value + for IEEE 802.16 WMAN interfaces as per IEEE Std 802.16f + is deprecated and ieee80216WMAN(237) should be used + instead."; + } + enum "sonetOverheadChannel" { + value 185; + description + "SONET Overhead Channel"; + } + enum "digitalWrapperOverheadChannel" { + value 186; + description + "Digital Wrapper"; + } + enum "aal2" { + value 187; + description + "ATM adaptation layer 2"; + } + enum "radioMAC" { + value 188; + description + "MAC layer over radio links"; + } + enum "atmRadio" { + value 189; + description + "ATM over radio links"; + } + enum "imt" { + value 190; + description + "Inter Machine Trunks"; + } + enum "mvl" { + value 191; + description + "Multiple Virtual Lines DSL"; + } + enum "reachDSL" { + value 192; + description + "Long Reach DSL"; + } + enum "frDlciEndPt" { + value 193; + description + "Frame Relay DLCI End Point"; + } + enum "atmVciEndPt" { + value 194; + description + "ATM VCI End Point"; + } + enum "opticalChannel" { + value 195; + description + "Optical Channel"; + } + enum "opticalTransport" { + value 196; + description + "Optical Transport"; + } + enum "propAtm" { + value 197; + description + "Proprietary ATM"; + } + enum "voiceOverCable" { + value 198; + description + "Voice Over Cable Interface"; + } + enum "infiniband" { + value 199; + description + "Infiniband"; + } + enum "teLink" { + value 200; + description + "TE Link"; + } + enum "q2931" { + value 201; + description + "Q.2931"; + } + enum "virtualTg" { + value 202; + description + "Virtual Trunk Group"; + } + enum "sipTg" { + value 203; + description + "SIP Trunk Group"; + } + enum "sipSig" { + value 204; + description + "SIP Signaling"; + } + enum "docsCableUpstreamChannel" { + value 205; + description + "CATV Upstream Channel"; + } + enum "econet" { + value 206; + description + "Acorn Econet"; + } + enum "pon155" { + value 207; + description + "FSAN 155Mb Symetrical PON interface"; + } + enum "pon622" { + value 208; + description + "FSAN622Mb Symetrical PON interface"; + } + enum "bridge" { + value 209; + description + "Transparent bridge interface"; + } + enum "linegroup" { + value 210; + description + "Interface common to multiple lines"; + } + enum "voiceEMFGD" { + value 211; + description + "voice E&M Feature Group D"; + } + enum "voiceFGDEANA" { + value 212; + description + "voice FGD Exchange Access North American"; + } + enum "voiceDID" { + value 213; + description + "voice Direct Inward Dialing"; + } + enum "mpegTransport" { + value 214; + description + "MPEG transport interface"; + } + enum "sixToFour" { + value 215; + status deprecated; + description + "6to4 interface (DEPRECATED)"; + reference + "RFC 4087 - IP Tunnel MIB"; + } + enum "gtp" { + value 216; + description + "GTP (GPRS Tunneling Protocol)"; + } + enum "pdnEtherLoop1" { + value 217; + description + "Paradyne EtherLoop 1"; + } + enum "pdnEtherLoop2" { + value 218; + description + "Paradyne EtherLoop 2"; + } + enum "opticalChannelGroup" { + value 219; + description + "Optical Channel Group"; + } + enum "homepna" { + value 220; + description + "HomePNA ITU-T G.989"; + } + enum "gfp" { + value 221; + description + "Generic Framing Procedure (GFP)"; + } + enum "ciscoISLvlan" { + value 222; + description + "Layer 2 Virtual LAN using Cisco ISL"; + } + enum "actelisMetaLOOP" { + value 223; + description + "Acteleis proprietary MetaLOOP High Speed Link"; + } + enum "fcipLink" { + value 224; + description + "FCIP Link"; + } + enum "rpr" { + value 225; + description + "Resilient Packet Ring Interface Type"; + } + enum "qam" { + value 226; + description + "RF Qam Interface"; + } + enum "lmp" { + value 227; + description + "Link Management Protocol"; + reference + "RFC 4327 - Link Management Protocol (LMP) Management + Information Base (MIB)"; + } + enum "cblVectaStar" { + value 228; + description + "Cambridge Broadband Networks Limited VectaStar"; + } + enum "docsCableMCmtsDownstream" { + value 229; + description + "CATV Modular CMTS Downstream Interface"; + } + enum "adsl2" { + value 230; + status deprecated; + description + "Asymmetric Digital Subscriber Loop Version 2 + (DEPRECATED/OBSOLETED - please use adsl2plus(238) + instead)"; + reference + "RFC 4706 - Definitions of Managed Objects for Asymmetric + Digital Subscriber Line 2 (ADSL2)"; + } + enum "macSecControlledIF" { + value 231; + description + "MACSecControlled"; + } + enum "macSecUncontrolledIF" { + value 232; + description + "MACSecUncontrolled"; + } + enum "aviciOpticalEther" { + value 233; + description + "Avici Optical Ethernet Aggregate"; + } + enum "atmbond" { + value 234; + description + "atmbond"; + } + enum "voiceFGDOS" { + value 235; + description + "voice FGD Operator Services"; + } + enum "mocaVersion1" { + value 236; + description + "MultiMedia over Coax Alliance (MoCA) Interface + as documented in information provided privately to IANA"; + } + enum "ieee80216WMAN" { + value 237; + description + "IEEE 802.16 WMAN interface"; + } + enum "adsl2plus" { + value 238; + description + "Asymmetric Digital Subscriber Loop Version 2, + Version 2 Plus and all variants"; + } + enum "dvbRcsMacLayer" { + value 239; + description + "DVB-RCS MAC Layer"; + reference + "RFC 5728 - The SatLabs Group DVB-RCS MIB"; + } + enum "dvbTdm" { + value 240; + description + "DVB Satellite TDM"; + reference + "RFC 5728 - The SatLabs Group DVB-RCS MIB"; + } + enum "dvbRcsTdma" { + value 241; + description + "DVB-RCS TDMA"; + reference + "RFC 5728 - The SatLabs Group DVB-RCS MIB"; + } + enum "x86Laps" { + value 242; + description + "LAPS based on ITU-T X.86/Y.1323"; + } + enum "wwanPP" { + value 243; + description + "3GPP WWAN"; + } + enum "wwanPP2" { + value 244; + description + "3GPP2 WWAN"; + } + enum "voiceEBS" { + value 245; + description + "voice P-phone EBS physical interface"; + } + enum "ifPwType" { + value 246; + description + "Pseudowire interface type"; + reference + "RFC 5601 - Pseudowire (PW) Management Information Base"; + } + enum "ilan" { + value 247; + description + "Internal LAN on a bridge per IEEE 802.1ap"; + } + enum "pip" { + value 248; + description + "Provider Instance Port on a bridge per IEEE 802.1ah PBB"; + } + enum "aluELP" { + value 249; + description + "Alcatel-Lucent Ethernet Link Protection"; + } + enum "gpon" { + value 250; + description + "Gigabit-capable passive optical networks (G-PON) as per + ITU-T G.948"; + } + enum "vdsl2" { + value 251; + description + "Very high speed digital subscriber line Version 2 + (as per ITU-T Recommendation G.993.2)"; + reference + "RFC 5650 - Definitions of Managed Objects for Very High + Speed Digital Subscriber Line 2 (VDSL2)"; + } + enum "capwapDot11Profile" { + value 252; + description + "WLAN Profile Interface"; + reference + "RFC 5834 - Control and Provisioning of Wireless Access + Points (CAPWAP) Protocol Binding MIB for + IEEE 802.11"; + } + enum "capwapDot11Bss" { + value 253; + description + "WLAN BSS Interface"; + reference + "RFC 5834 - Control and Provisioning of Wireless Access + Points (CAPWAP) Protocol Binding MIB for + IEEE 802.11"; + } + enum "capwapWtpVirtualRadio" { + value 254; + description + "WTP Virtual Radio Interface"; + reference + "RFC 5833 - Control and Provisioning of Wireless Access + Points (CAPWAP) Protocol Base MIB"; + } + enum "bits" { + value 255; + description + "bitsport"; + } + enum "docsCableUpstreamRfPort" { + value 256; + description + "DOCSIS CATV Upstream RF Port"; + } + enum "cableDownstreamRfPort" { + value 257; + description + "CATV downstream RF port"; + } + enum "vmwareVirtualNic" { + value 258; + description + "VMware Virtual Network Interface"; + } + enum "ieee802154" { + value 259; + description + "IEEE 802.15.4 WPAN interface"; + reference + "IEEE 802.15.4-2006"; + } + enum "otnOdu" { + value 260; + description + "OTN Optical Data Unit"; + } + enum "otnOtu" { + value 261; + description + "OTN Optical channel Transport Unit"; + } + enum "ifVfiType" { + value 262; + description + "VPLS Forwarding Instance Interface Type"; + } + enum "g9981" { + value 263; + description + "G.998.1 bonded interface"; + } + enum "g9982" { + value 264; + description + "G.998.2 bonded interface"; + } + enum "g9983" { + value 265; + description + "G.998.3 bonded interface"; + } + enum "aluEpon" { + value 266; + description + "Ethernet Passive Optical Networks (E-PON)"; + } + enum "aluEponOnu" { + value 267; + description + "EPON Optical Network Unit"; + } + enum "aluEponPhysicalUni" { + value 268; + description + "EPON physical User to Network interface"; + } + enum "aluEponLogicalLink" { + value 269; + description + "The emulation of a point-to-point link over the EPON + layer"; + } + enum "aluGponOnu" { + value 270; + description + "GPON Optical Network Unit"; + reference + "ITU-T G.984.2"; + } + enum "aluGponPhysicalUni" { + value 271; + description + "GPON physical User to Network interface"; + reference + "ITU-T G.984.2"; + } + enum "vmwareNicTeam" { + value 272; + description + "VMware NIC Team"; + } + // value 273 reserved by IANA + } + description + "This data type is used as the syntax of the 'type' + leaf in the 'interface' list in the YANG module + ietf-interface. + + The definition of this typedef with the + addition of newly assigned values is published + periodically by the IANA, in either the Assigned + Numbers RFC, or some derivative of it specific to + Internet Network Management number assignments. (The + latest arrangements can be obtained by contacting the + IANA.) + + Requests for new values should be made to IANA via + email (iana&iana.org)."; + reference + "IANA ifType definitions registry. + "; + } +} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/modules/ietf-inet-types.yang b/opendaylight/md-sal/sal-rest-connector/src/test/resources/modules/ietf-inet-types.yang new file mode 100644 index 0000000000..de20febbb7 --- /dev/null +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/modules/ietf-inet-types.yang @@ -0,0 +1,418 @@ + module ietf-inet-types { + + namespace "urn:ietf:params:xml:ns:yang:ietf-inet-types"; + prefix "inet"; + + organization + "IETF NETMOD (NETCONF Data Modeling Language) Working Group"; + + contact + "WG Web: + WG List: + + WG Chair: David Partain + + + WG Chair: David Kessens + + + Editor: Juergen Schoenwaelder + "; + + description + "This module contains a collection of generally useful derived + YANG data types for Internet addresses and related things. + + Copyright (c) 2010 IETF Trust and the persons identified as + authors of the code. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, is permitted pursuant to, and subject to the license + terms contained in, the Simplified BSD License set forth in Section + 4.c of the IETF Trust's Legal Provisions Relating to IETF Documents + (http://trustee.ietf.org/license-info). + + This version of this YANG module is part of RFC 6021; see + the RFC itself for full legal notices."; + + revision 2010-09-24 { + description + "Initial revision."; + reference + "RFC 6021: Common YANG Data Types"; + } + + /*** collection of protocol field related types ***/ + + typedef ip-version { + type enumeration { + enum unknown { + value "0"; + description + "An unknown or unspecified version of the Internet protocol."; + } + enum ipv4 { + value "1"; + description + "The IPv4 protocol as defined in RFC 791."; + } + enum ipv6 { + value "2"; + description + "The IPv6 protocol as defined in RFC 2460."; + } + } + description + "This value represents the version of the IP protocol. + + In the value set and its semantics, this type is equivalent + to the InetVersion textual convention of the SMIv2."; + reference + "RFC 791: Internet Protocol + RFC 2460: Internet Protocol, Version 6 (IPv6) Specification + RFC 4001: Textual Conventions for Internet Network Addresses"; + } + + typedef dscp { + type uint8 { + range "0..63"; + } + description + "The dscp type represents a Differentiated Services Code-Point + that may be used for marking packets in a traffic stream. + + In the value set and its semantics, this type is equivalent + to the Dscp textual convention of the SMIv2."; + reference + "RFC 3289: Management Information Base for the Differentiated + Services Architecture + RFC 2474: Definition of the Differentiated Services Field + (DS Field) in the IPv4 and IPv6 Headers + RFC 2780: IANA Allocation Guidelines For Values In + the Internet Protocol and Related Headers"; + } + + typedef ipv6-flow-label { + type uint32 { + range "0..1048575"; + } + description + "The flow-label type represents flow identifier or Flow Label + in an IPv6 packet header that may be used to discriminate + traffic flows. + + In the value set and its semantics, this type is equivalent + to the IPv6FlowLabel textual convention of the SMIv2."; + reference + "RFC 3595: Textual Conventions for IPv6 Flow Label + RFC 2460: Internet Protocol, Version 6 (IPv6) Specification"; + } + + typedef port-number { + type uint16 { + range "0..65535"; + } + description + "The port-number type represents a 16-bit port number of an + Internet transport layer protocol such as UDP, TCP, DCCP, or + SCTP. Port numbers are assigned by IANA. A current list of + all assignments is available from . + + Note that the port number value zero is reserved by IANA. In + situations where the value zero does not make sense, it can + be excluded by subtyping the port-number type. + + In the value set and its semantics, this type is equivalent + to the InetPortNumber textual convention of the SMIv2."; + reference + "RFC 768: User Datagram Protocol + RFC 793: Transmission Control Protocol + RFC 4960: Stream Control Transmission Protocol + RFC 4340: Datagram Congestion Control Protocol (DCCP) + RFC 4001: Textual Conventions for Internet Network Addresses"; + } + + /*** collection of autonomous system related types ***/ + + typedef as-number { + type uint32; + description + "The as-number type represents autonomous system numbers + which identify an Autonomous System (AS). An AS is a set + of routers under a single technical administration, using + an interior gateway protocol and common metrics to route + packets within the AS, and using an exterior gateway + protocol to route packets to other ASs'. IANA maintains + the AS number space and has delegated large parts to the + regional registries. + + Autonomous system numbers were originally limited to 16 + bits. BGP extensions have enlarged the autonomous system + number space to 32 bits. This type therefore uses an uint32 + base type without a range restriction in order to support + a larger autonomous system number space. + + In the value set and its semantics, this type is equivalent + to the InetAutonomousSystemNumber textual convention of + the SMIv2."; + reference + "RFC 1930: Guidelines for creation, selection, and registration + of an Autonomous System (AS) + RFC 4271: A Border Gateway Protocol 4 (BGP-4) + RFC 4893: BGP Support for Four-octet AS Number Space + RFC 4001: Textual Conventions for Internet Network Addresses"; + } + + /*** collection of IP address and hostname related types ***/ + + typedef ip-address { + type union { + type inet:ipv4-address; + type inet:ipv6-address; + } + description + "The ip-address type represents an IP address and is IP + version neutral. The format of the textual representations + implies the IP version."; + } + + typedef ipv4-address { + type string { + pattern + '(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}' + + '([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])' + + '(%[\p{N}\p{L}]+)?'; + } + description + "The ipv4-address type represents an IPv4 address in + dotted-quad notation. The IPv4 address may include a zone + index, separated by a % sign. + + The zone index is used to disambiguate identical address + values. For link-local addresses, the zone index will + typically be the interface index number or the name of an + interface. If the zone index is not present, the default + zone of the device will be used. + + The canonical format for the zone index is the numerical + format"; + } + + typedef ipv6-address { + type string { + pattern '((:|[0-9a-fA-F]{0,4}):)([0-9a-fA-F]{0,4}:){0,5}' + + '((([0-9a-fA-F]{0,4}:)?(:|[0-9a-fA-F]{0,4}))|' + + '(((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\.){3}' + + '(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])))' + + '(%[\p{N}\p{L}]+)?'; + pattern '(([^:]+:){6}(([^:]+:[^:]+)|(.*\..*)))|' + + '((([^:]+:)*[^:]+)?::(([^:]+:)*[^:]+)?)' + + '(%.+)?'; + } + description + "The ipv6-address type represents an IPv6 address in full, + mixed, shortened, and shortened-mixed notation. The IPv6 + address may include a zone index, separated by a % sign. + + The zone index is used to disambiguate identical address + values. For link-local addresses, the zone index will + typically be the interface index number or the name of an + interface. If the zone index is not present, the default + zone of the device will be used. + + The canonical format of IPv6 addresses uses the compressed + format described in RFC 4291, Section 2.2, item 2 with the + following additional rules: the :: substitution must be + applied to the longest sequence of all-zero 16-bit chunks + in an IPv6 address. If there is a tie, the first sequence + of all-zero 16-bit chunks is replaced by ::. Single + all-zero 16-bit chunks are not compressed. The canonical + format uses lowercase characters and leading zeros are + not allowed. The canonical format for the zone index is + the numerical format as described in RFC 4007, Section + 11.2."; + reference + "RFC 4291: IP Version 6 Addressing Architecture + RFC 4007: IPv6 Scoped Address Architecture + RFC 5952: A Recommendation for IPv6 Address Text Representation"; + } + + typedef ip-prefix { + type union { + type inet:ipv4-prefix; + type inet:ipv6-prefix; + } + description + "The ip-prefix type represents an IP prefix and is IP + version neutral. The format of the textual representations + implies the IP version."; + } + + typedef ipv4-prefix { + type string { + pattern + '(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}' + + '([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])' + + '/(([0-9])|([1-2][0-9])|(3[0-2]))'; + } + description + "The ipv4-prefix type represents an IPv4 address prefix. + The prefix length is given by the number following the + slash character and must be less than or equal to 32. + + A prefix length value of n corresponds to an IP address + mask that has n contiguous 1-bits from the most + significant bit (MSB) and all other bits set to 0. + + The canonical format of an IPv4 prefix has all bits of + the IPv4 address set to zero that are not part of the + IPv4 prefix."; + } + + typedef ipv6-prefix { + type string { + pattern '((:|[0-9a-fA-F]{0,4}):)([0-9a-fA-F]{0,4}:){0,5}' + + '((([0-9a-fA-F]{0,4}:)?(:|[0-9a-fA-F]{0,4}))|' + + '(((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\.){3}' + + '(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])))' + + '(/(([0-9])|([0-9]{2})|(1[0-1][0-9])|(12[0-8])))'; + pattern '(([^:]+:){6}(([^:]+:[^:]+)|(.*\..*)))|' + + '((([^:]+:)*[^:]+)?::(([^:]+:)*[^:]+)?)' + + '(/.+)'; + } + description + "The ipv6-prefix type represents an IPv6 address prefix. + The prefix length is given by the number following the + slash character and must be less than or equal 128. + + A prefix length value of n corresponds to an IP address + mask that has n contiguous 1-bits from the most + significant bit (MSB) and all other bits set to 0. + + The IPv6 address should have all bits that do not belong + to the prefix set to zero. + + The canonical format of an IPv6 prefix has all bits of + the IPv6 address set to zero that are not part of the + IPv6 prefix. Furthermore, IPv6 address is represented + in the compressed format described in RFC 4291, Section + 2.2, item 2 with the following additional rules: the :: + substitution must be applied to the longest sequence of + all-zero 16-bit chunks in an IPv6 address. If there is + a tie, the first sequence of all-zero 16-bit chunks is + replaced by ::. Single all-zero 16-bit chunks are not + compressed. The canonical format uses lowercase + characters and leading zeros are not allowed."; + reference + "RFC 4291: IP Version 6 Addressing Architecture"; + } + + /*** collection of domain name and URI types ***/ + + typedef domain-name { + type string { + pattern '((([a-zA-Z0-9_]([a-zA-Z0-9\-_]){0,61})?[a-zA-Z0-9]\.)*' + + '([a-zA-Z0-9_]([a-zA-Z0-9\-_]){0,61})?[a-zA-Z0-9]\.?)' + + '|\.'; + length "1..253"; + } + description + "The domain-name type represents a DNS domain name. The + name SHOULD be fully qualified whenever possible. + + Internet domain names are only loosely specified. Section + 3.5 of RFC 1034 recommends a syntax (modified in Section + 2.1 of RFC 1123). The pattern above is intended to allow + for current practice in domain name use, and some possible + future expansion. It is designed to hold various types of + domain names, including names used for A or AAAA records + (host names) and other records, such as SRV records. Note + that Internet host names have a stricter syntax (described + in RFC 952) than the DNS recommendations in RFCs 1034 and + 1123, and that systems that want to store host names in + schema nodes using the domain-name type are recommended to + adhere to this stricter standard to ensure interoperability. + + The encoding of DNS names in the DNS protocol is limited + to 255 characters. Since the encoding consists of labels + prefixed by a length bytes and there is a trailing NULL + byte, only 253 characters can appear in the textual dotted + notation. + + The description clause of schema nodes using the domain-name + type MUST describe when and how these names are resolved to + IP addresses. Note that the resolution of a domain-name value + may require to query multiple DNS records (e.g., A for IPv4 + and AAAA for IPv6). The order of the resolution process and + which DNS record takes precedence can either be defined + explicitely or it may depend on the configuration of the + resolver. + + Domain-name values use the US-ASCII encoding. Their canonical + format uses lowercase US-ASCII characters. Internationalized + domain names MUST be encoded in punycode as described in RFC + 3492"; + reference + "RFC 952: DoD Internet Host Table Specification + RFC 1034: Domain Names - Concepts and Facilities + RFC 1123: Requirements for Internet Hosts -- Application + and Support + RFC 2782: A DNS RR for specifying the location of services + (DNS SRV) + RFC 3492: Punycode: A Bootstring encoding of Unicode for + Internationalized Domain Names in Applications + (IDNA) + RFC 5891: Internationalizing Domain Names in Applications + (IDNA): Protocol"; + } + + typedef host { + type union { + type inet:ip-address; + type inet:domain-name; + } + description + "The host type represents either an IP address or a DNS + domain name."; + } + + typedef uri { + type string; + description + "The uri type represents a Uniform Resource Identifier + (URI) as defined by STD 66. + + Objects using the uri type MUST be in US-ASCII encoding, + and MUST be normalized as described by RFC 3986 Sections + 6.2.1, 6.2.2.1, and 6.2.2.2. All unnecessary + percent-encoding is removed, and all case-insensitive + characters are set to lowercase except for hexadecimal + digits, which are normalized to uppercase as described in + Section 6.2.2.1. + + The purpose of this normalization is to help provide + unique URIs. Note that this normalization is not + sufficient to provide uniqueness. Two URIs that are + textually distinct after this normalization may still be + equivalent. + + Objects using the uri type may restrict the schemes that + they permit. For example, 'data:' and 'urn:' schemes + might not be appropriate. + + A zero-length URI is not a valid URI. This can be used to + express 'URI absent' where required. + + In the value set and its semantics, this type is equivalent + to the Uri SMIv2 textual convention defined in RFC 5017."; + reference + "RFC 3986: Uniform Resource Identifier (URI): Generic Syntax + RFC 3305: Report from the Joint W3C/IETF URI Planning Interest + Group: Uniform Resource Identifiers (URIs), URLs, + and Uniform Resource Names (URNs): Clarifications + and Recommendations + RFC 5017: MIB Textual Conventions for Uniform Resource + Identifiers (URIs)"; + } + + } diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/modules/ietf-interfaces@2013-07-04.yang b/opendaylight/md-sal/sal-rest-connector/src/test/resources/modules/ietf-interfaces@2013-07-04.yang new file mode 100644 index 0000000000..9db753c440 --- /dev/null +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/modules/ietf-interfaces@2013-07-04.yang @@ -0,0 +1,673 @@ +module ietf-interfaces { + + namespace "urn:ietf:params:xml:ns:yang:ietf-interfaces"; + prefix if; + + import ietf-yang-types { + prefix yang; + } + import iana-if-type { + prefix ianaift; + } + + organization + "IETF NETMOD (NETCONF Data Modeling Language) Working Group"; + + contact + "WG Web: + WG List: + + WG Chair: David Kessens + + + WG Chair: Juergen Schoenwaelder + + + Editor: Martin Bjorklund + "; + + description + "This module contains a collection of YANG definitions for + managing network interfaces. + + Copyright (c) 2013 IETF Trust and the persons identified as + authors of the code. All rights reserved. + + Redistribution and use in source and binary forms, with or + without modification, is permitted pursuant to, and subject + to the license terms contained in, the Simplified BSD License + set forth in Section 4.c of the IETF Trust's Legal Provisions + Relating to IETF Documents + (http://trustee.ietf.org/license-info). + + This version of this YANG module is part of RFC XXXX; see + the RFC itself for full legal notices."; + + // RFC Ed.: replace XXXX with actual RFC number and remove this + // note. + + // RFC Ed.: update the date below with the date of RFC publication + // and remove this note. + revision 2013-07-04 { + description + "Initial revision."; + reference + "RFC XXXX: A YANG Data Model for Interface Management"; + } + + /* Typedefs */ + + typedef interface-ref { + type leafref { + path "/if:interfaces/if:interface/if:name"; + } + description + "This type is used by data models that need to reference + configured interfaces."; + } + + typedef interface-state-ref { + type leafref { + path "/if:interfaces-state/if:interface/if:name"; + } + description + "This type is used by data models that need to reference + the operationally present interfaces."; + } + + /* Features */ + + feature arbitrary-names { + description + "This feature indicates that the device allows user-controlled + interfaces to be named arbitrarily."; + } + + feature pre-provisioning { + description + "This feature indicates that the device supports + pre-provisioning of interface configuration, i.e., it is + possible to configure an interface whose physical interface + hardware is not present on the device."; + } + + feature if-mib { + description + "This feature indicates that the device implements IF-MIB."; + reference + "RFC 2863: The Interfaces Group MIB"; + } + + /* Data nodes */ + + container interfaces { + description + "Interface configuration parameters."; + + list interface { + key "name"; + + description + "The list of configured interfaces on the device. + + The operational state of an interface is available in the + /interfaces-state/interface list. If the configuration of a + system-controlled interface cannot be used by the system + (e.g., the interface hardware present does not match the + interface type), then the configuration is not applied to + the system-controlled interface shown in the + /interfaces-state/interface list. If the the configuration + of a user-controlled interface cannot be used by the system, + the configured interface is not instantiated in the + /interfaces-state/interface list."; + + leaf name { + type string; + description + "The name of the interface. + + A device MAY restrict the allowed values for this leaf, + possibly depending on the type of the interface. + + For system-controlled interfaces, this leaf is the + device-specific name of the interface. The 'config false' + list /interfaces-state/interface contains the currently + existing interfaces on the device. + + If a client tries to create configuration for a + system-controlled interface that is not present in the + /interfaces-state/interface list, the server MAY reject + the request, if the implementation does not support + pre-provisioning of interfaces, or if the name refers to + an interface that can never exist in the system. A + NETCONF server MUST reply with an rpc-error with the + error-tag 'invalid-value' in this case. + + If the device supports pre-provisioning of interface + configuration, the feature 'pre-provisioning' is + advertised. + + If the device allows arbitrarily named user-controlled + interfaces, the feature 'arbitrary-names' is advertised. + + When a configured user-controlled interface is created by + the system, it is instantiated with the same name in the + /interface-state/interface list. Since the name in that + list MAY be mapped to ifName by an implementation, such an + implementation MUST restrict the allowed values for this + leaf so that it matches the restrictions of ifName. + + If a NETCONF server that implements this restriction is + sent a value that doesn't match the restriction, it MUST + reply with an rpc-error with the error-tag + 'invalid-value'."; + } + + leaf description { + type string; + description + "A textual description of the interface. + + This leaf MAY be mapped to ifAlias by an implementation. + Such an implementation MUST restrict the allowed values + for this leaf so that it matches the restrictions of + ifAlias. + + If a NETCONF server that implements this restriction is + sent a value that doesn't match the restriction, it MUST + reply with an rpc-error with the error-tag + 'invalid-value'. + + Since ifAlias is defined to be stored in non-volatile + storage, the MIB implementation MUST map ifAlias to the + value of 'description' in the persistently stored + datastore. + + Specifically, if the device supports ':startup', when + ifAlias is read the device MUST return the value of + 'description' in the 'startup' datastore, and when it is + written, it MUST be written to the 'running' and 'startup' + datastores. Note that it is up to the implementation if + it modifies this single leaf in 'startup', or if it + performs an implicit copy-config from 'running' to + 'startup'. + + If the device does not support ':startup', ifAlias MUST + be mapped to the 'description' leaf in the 'running' + datastore."; + reference + "RFC 2863: The Interfaces Group MIB - ifAlias"; + } + + leaf type { + type ianaift:iana-if-type; + mandatory true; + description + "The type of the interface. + + When an interface entry is created, a server MAY + initialize the type leaf with a valid value, e.g., if it + is possible to derive the type from the name of the + interface. + + If a client tries to set the type of an interface to a + value that can never be used by the system, e.g., if the + type is not supported or if the type does not match the + name of the interface, the server MUST reject the request. + A NETCONF server MUST reply with an rpc-error with the + error-tag 'invalid-value' in this case."; + reference + "RFC 2863: The Interfaces Group MIB - ifType"; + } + + leaf enabled { + type boolean; + default "true"; + description + "This leaf contains the configured, desired state of the + interface. + + Systems that implement the IF-MIB use the value of this + leaf in the 'running' datastore to set + IF-MIB.ifAdminStatus to 'up' or 'down' after an ifEntry + has been initialized, as described in RFC 2863. + + Changes in this leaf in the 'running' datastore are + reflected in ifAdminStatus, but if ifAdminStatus is + changed over SNMP, this leaf is not affected."; + reference + "RFC 2863: The Interfaces Group MIB - ifAdminStatus"; + } + + leaf link-up-down-trap-enable { + if-feature if-mib; + type enumeration { + enum enabled { + value 1; + } + enum disabled { + value 2; + } + } + description + "Controls whether linkUp/linkDown SNMP notifications + should be generated for this interface. + + If this node is not configured, the value 'enabled' is + operationally used by the server for interfaces which do + not operate on top of any other interface (i.e., there are + no 'lower-layer-if' entries), and 'disabled' otherwise."; + reference + "RFC 2863: The Interfaces Group MIB - + ifLinkUpDownTrapEnable"; + } + } + } + + container interfaces-state { + config false; + description + "Data nodes for the operational state of interfaces."; + + list interface { + key "name"; + + description + "The list of interfaces on the device. + + System-controlled interfaces created by the system are + always present in this list, whether they are configured or + not."; + + leaf name { + type string; + description + "The name of the interface. + + This leaf MAY be mapped to ifName by an implementation."; + reference + "RFC 2863: The Interfaces Group MIB - ifName"; + } + + leaf type { + type ianaift:iana-if-type; + mandatory true; + description + "The type of the interface."; + reference + "RFC 2863: The Interfaces Group MIB - ifType"; + } + + leaf admin-status { + if-feature if-mib; + type enumeration { + enum up { + value 1; + description + "Ready to pass packets."; + } + enum down { + value 2; + description + "Not ready to pass packets and not in some test mode."; + } + enum testing { + value 3; + description + "In some test mode."; + } + } + mandatory true; + description + "The desired state of the interface. + + This leaf has the same read semantics as ifAdminStatus."; + reference + "RFC 2863: The Interfaces Group MIB - ifAdminStatus"; + } + + leaf oper-status { + type enumeration { + enum up { + value 1; + description + "Ready to pass packets."; + } + enum down { + value 2; + description + "The interface does not pass any packets."; + } + enum testing { + value 3; + description + "In some test mode. No operational packets can + be passed."; + } + enum unknown { + value 4; + description + "Status cannot be determined for some reason."; + } + enum dormant { + value 5; + description + "Waiting for some external event."; + } + enum not-present { + value 6; + description + "Some component (typically hardware) is missing."; + } + enum lower-layer-down { + value 7; + description + "Down due to state of lower-layer interface(s)."; + } + } + mandatory true; + description + "The current operational state of the interface. + + This leaf has the same semantics as ifOperStatus."; + reference + "RFC 2863: The Interfaces Group MIB - ifOperStatus"; + } + + leaf last-change { + type yang:date-and-time; + description + "The time the interface entered its current operational + state. If the current state was entered prior to the + last re-initialization of the local network management + subsystem, then this node is not present."; + reference + "RFC 2863: The Interfaces Group MIB - ifLastChange"; + } + + leaf if-index { + if-feature if-mib; + type int32 { + range "1..2147483647"; + } + mandatory true; + description + "The ifIndex value for the ifEntry represented by this + interface."; + reference + "RFC 2863: The Interfaces Group MIB - ifIndex"; + } + + leaf phys-address { + type yang:phys-address; + description + "The interface's address at its protocol sub-layer. For + example, for an 802.x interface, this object normally + contains a MAC address. The interface's media-specific + modules must define the bit and byte ordering and the + format of the value of this object. For interfaces that do + not have such an address (e.g., a serial line), this node + is not present."; + reference + "RFC 2863: The Interfaces Group MIB - ifPhysAddress"; + } + + leaf-list higher-layer-if { + type interface-state-ref; + description + "A list of references to interfaces layered on top of this + interface."; + reference + "RFC 2863: The Interfaces Group MIB - ifStackTable"; + } + + leaf-list lower-layer-if { + type interface-state-ref; + description + "A list of references to interfaces layered underneath this + interface."; + reference + "RFC 2863: The Interfaces Group MIB - ifStackTable"; + } + + leaf speed { + type yang:gauge64; + units "bits / second"; + description + "An estimate of the interface's current bandwidth in bits + per second. For interfaces that do not vary in + bandwidth or for those where no accurate estimation can + be made, this node should contain the nominal bandwidth. + For interfaces that have no concept of bandwidth, this + node is not present."; + reference + "RFC 2863: The Interfaces Group MIB - + ifSpeed, ifHighSpeed"; + } + + container statistics { + description + "A collection of interface-related statistics objects."; + + leaf discontinuity-time { + type yang:date-and-time; + mandatory true; + description + "The time on the most recent occasion at which any one or + more of this interface's counters suffered a + discontinuity. If no such discontinuities have occurred + since the last re-initialization of the local management + subsystem, then this node contains the time the local + management subsystem re-initialized itself."; + } + + leaf in-octets { + type yang:counter64; + description + "The total number of octets received on the interface, + including framing characters. + + Discontinuities in the value of this counter can occur + at re-initialization of the management system, and at + other times as indicated by the value of + 'discontinuity-time'."; + reference + "RFC 2863: The Interfaces Group MIB - ifHCInOctets"; + } + leaf in-unicast-pkts { + type yang:counter64; + description + "The number of packets, delivered by this sub-layer to a + higher (sub-)layer, which were not addressed to a + multicast or broadcast address at this sub-layer. + + Discontinuities in the value of this counter can occur + at re-initialization of the management system, and at + other times as indicated by the value of + 'discontinuity-time'."; + reference + "RFC 2863: The Interfaces Group MIB - ifHCInUcastPkts"; + } + leaf in-broadcast-pkts { + type yang:counter64; + description + "The number of packets, delivered by this sub-layer to a + higher (sub-)layer, which were addressed to a broadcast + address at this sub-layer. + + Discontinuities in the value of this counter can occur + at re-initialization of the management system, and at + other times as indicated by the value of + 'discontinuity-time'."; + reference + "RFC 2863: The Interfaces Group MIB - + ifHCInBroadcastPkts"; + } + leaf in-multicast-pkts { + type yang:counter64; + description + "The number of packets, delivered by this sub-layer to a + higher (sub-)layer, which were addressed to a multicast + address at this sub-layer. For a MAC layer protocol, + this includes both Group and Functional addresses. + + Discontinuities in the value of this counter can occur + at re-initialization of the management system, and at + other times as indicated by the value of + 'discontinuity-time'."; + reference + "RFC 2863: The Interfaces Group MIB - + ifHCInMulticastPkts"; + } + leaf in-discards { + type yang:counter32; + description + "The number of inbound packets which were chosen to be + discarded even though no errors had been detected to + prevent their being deliverable to a higher-layer + protocol. One possible reason for discarding such a + packet could be to free up buffer space. + + Discontinuities in the value of this counter can occur + at re-initialization of the management system, and at + other times as indicated by the value of + 'discontinuity-time'."; + reference + "RFC 2863: The Interfaces Group MIB - ifInDiscards"; + } + leaf in-errors { + type yang:counter32; + description + "For packet-oriented interfaces, the number of inbound + packets that contained errors preventing them from being + deliverable to a higher-layer protocol. For character- + oriented or fixed-length interfaces, the number of + inbound transmission units that contained errors + preventing them from being deliverable to a higher-layer + protocol. + + Discontinuities in the value of this counter can occur + at re-initialization of the management system, and at + other times as indicated by the value of + 'discontinuity-time'."; + reference + "RFC 2863: The Interfaces Group MIB - ifInErrors"; + } + leaf in-unknown-protos { + type yang:counter32; + description + "For packet-oriented interfaces, the number of packets + received via the interface which were discarded because + of an unknown or unsupported protocol. For + character-oriented or fixed-length interfaces that + support protocol multiplexing the number of transmission + units received via the interface which were discarded + because of an unknown or unsupported protocol. For any + interface that does not support protocol multiplexing, + this counter is not present. + Discontinuities in the value of this counter can occur + at re-initialization of the management system, and at + other times as indicated by the value of + 'discontinuity-time'."; + reference + "RFC 2863: The Interfaces Group MIB - ifInUnknownProtos"; + } + + leaf out-octets { + type yang:counter64; + description + "The total number of octets transmitted out of the + interface, including framing characters. + + Discontinuities in the value of this counter can occur + at re-initialization of the management system, and at + other times as indicated by the value of + 'discontinuity-time'."; + reference + "RFC 2863: The Interfaces Group MIB - ifHCOutOctets"; + } + leaf out-unicast-pkts { + type yang:counter64; + description + "The total number of packets that higher-level protocols + requested be transmitted, and which were not addressed + to a multicast or broadcast address at this sub-layer, + including those that were discarded or not sent. + + Discontinuities in the value of this counter can occur + at re-initialization of the management system, and at + other times as indicated by the value of + 'discontinuity-time'."; + reference + "RFC 2863: The Interfaces Group MIB - ifHCOutUcastPkts"; + } + leaf out-broadcast-pkts { + type yang:counter64; + description + "The total number of packets that higher-level protocols + requested be transmitted, and which were addressed to a + broadcast address at this sub-layer, including those + that were discarded or not sent. + + Discontinuities in the value of this counter can occur + at re-initialization of the management system, and at + other times as indicated by the value of + 'discontinuity-time'."; + reference + "RFC 2863: The Interfaces Group MIB - + ifHCOutBroadcastPkts"; + } + leaf out-multicast-pkts { + type yang:counter64; + description + "The total number of packets that higher-level protocols + requested be transmitted, and which were addressed to a + multicast address at this sub-layer, including those + that were discarded or not sent. For a MAC layer + protocol, this includes both Group and Functional + addresses. + + Discontinuities in the value of this counter can occur + at re-initialization of the management system, and at + other times as indicated by the value of + 'discontinuity-time'."; + reference + "RFC 2863: The Interfaces Group MIB - + ifHCOutMulticastPkts"; + } + leaf out-discards { + type yang:counter32; + description + "The number of outbound packets which were chosen to be + discarded even though no errors had been detected to + prevent their being transmitted. One possible reason + for discarding such a packet could be to free up buffer + space. + + Discontinuities in the value of this counter can occur + at re-initialization of the management system, and at + other times as indicated by the value of + 'discontinuity-time'."; + reference + "RFC 2863: The Interfaces Group MIB - ifOutDiscards"; + } + leaf out-errors { + type yang:counter32; + description + "For packet-oriented interfaces, the number of outbound + packets that could not be transmitted because of errors. + For character-oriented or fixed-length interfaces, the + number of outbound transmission units that could not be + transmitted because of errors. + + Discontinuities in the value of this counter can occur + at re-initialization of the management system, and at + other times as indicated by the value of + 'discontinuity-time'."; + reference + "RFC 2863: The Interfaces Group MIB - ifOutErrors"; + } + } + } + } +} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/modules/ietf-restconf@2013-10-19.yang b/opendaylight/md-sal/sal-rest-connector/src/test/resources/modules/ietf-restconf@2013-10-19.yang new file mode 100644 index 0000000000..16766b0979 --- /dev/null +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/modules/ietf-restconf@2013-10-19.yang @@ -0,0 +1,684 @@ +module ietf-restconf { + namespace "urn:ietf:params:xml:ns:yang:ietf-restconf"; + prefix "restconf"; + + import ietf-yang-types { prefix yang; } + import ietf-inet-types { prefix inet; } + + organization + "IETF NETCONF (Network Configuration) Working Group"; + + contact + "Editor: Andy Bierman + + + Editor: Martin Bjorklund + + + Editor: Kent Watsen + + + Editor: Rex Fernando + "; + + description + "This module contains conceptual YANG specifications + for the YANG Patch and error content that is used in + RESTCONF protocol messages. A conceptual container + representing the RESTCONF API nodes (media type + application/yang.api). + + Note that the YANG definitions within this module do not + represent configuration data of any kind. + The YANG grouping statements provide a normative syntax + for XML and JSON message encoding purposes. + Copyright (c) 2013 IETF Trust and the persons identified as + authors of the code. All rights reserved. + + Redistribution and use in source and binary forms, with or + without modification, is permitted pursuant to, and subject + to the license terms contained in, the Simplified BSD License + set forth in Section 4.c of the IETF Trust's Legal Provisions + Relating to IETF Documents + (http://trustee.ietf.org/license-info). + + This version of this YANG module is part of RFC XXXX; see + the RFC itself for full legal notices."; + + // RFC Ed.: replace XXXX with actual RFC number and remove this + // note. + + // RFC Ed.: remove this note + // Note: extracted from draft-bierman-netconf-restconf-02.txt + + // RFC Ed.: update the date below with the date of RFC publication + // and remove this note. + revision 2013-10-19 { + description + "Initial revision."; + reference + "RFC XXXX: RESTCONF Protocol."; + } + + typedef data-resource-identifier { + type string { + length "1 .. max"; + } + description + "Contains a Data Resource Identifier formatted string + to identify a specific data node. The data node that + uses this data type SHOULD define the document root + for data resource identifiers. The default document + root is the target datastore conceptual root node. + Data resource identifiers are defined relative to + this document root."; + reference + "RFC XXXX: [sec. 5.3.1.1 ABNF For Data Resource Identifiers]"; + } + + // this typedef is TBD; not currently used + typedef datastore-identifier { + type union { + type enumeration { + enum candidate { + description + "Identifies the NETCONF shared candidate datastore."; + reference + "RFC 6241, section 8.3"; + } + enum running { + description + "Identifies the NETCONF running datastore."; + reference + "RFC 6241, section 5.1"; + } + enum startup { + description + "Identifies the NETCONF startup datastore."; + reference + "RFC 6241, section 8.7"; + } + } + type string; + } + description + "Contains a string to identify a specific datastore. + The enumerated datastore identifier values are + reserved for standard datastore names."; + } + + typedef revision-identifier { + type string { + pattern '\d{4}-\d{2}-\d{2}'; + } + description + "Represents a specific date in YYYY-MM-DD format. + TBD: make pattern more precise to exclude leading zeros."; + } + + grouping yang-patch { + description + "A grouping that contains a YANG container + representing the syntax and semantics of a + YANG Patch edit request message."; + + container yang-patch { + description + "Represents a conceptual sequence of datastore edits, + called a patch. Each patch is given a client-assigned + patch identifier. Each edit MUST be applied + in ascending order, and all edits MUST be applied. + If any errors occur, then the target datastore MUST NOT + be changed by the patch operation. + + A patch MUST be validated by the server to be a + well-formed message before any of the patch edits + are validated or attempted. + + YANG datastore validation (defined in RFC 6020, section + 8.3.3) is performed after all edits have been + individually validated. + + It is possible for a datastore constraint violation to occur + due to any node in the datastore, including nodes not + included in the edit list. Any validation errors MUST + be reported in the reply message."; + + reference + "RFC 6020, section 8.3."; + + leaf patch-id { + type string; + description + "An arbitrary string provided by the client to identify + the entire patch. This value SHOULD be present in any + audit logging records generated by the server for the + patch. Error messages returned by the server pertaining + to this patch will be identified by this patch-id value."; + } + + leaf comment { + type string { + length "0 .. 1024"; + } + description + "An arbitrary string provided by the client to describe + the entire patch. This value SHOULD be present in any + audit logging records generated by the server for the + patch."; + } + + list edit { + key edit-id; + ordered-by user; + + description + "Represents one edit within the YANG Patch + request message."; + leaf edit-id { + type string; + description + "Arbitrary string index for the edit. + Error messages returned by the server pertaining + to a specific edit will be identified by this + value."; + } + + leaf operation { + type enumeration { + enum create { + description + "The target data node is created using the + supplied value, only if it does not already + exist."; + } + enum delete { + description + "Delete the target node, only if the data resource + currently exists, otherwise return an error."; + } + enum insert { + description + "Insert the supplied value into a user-ordered + list or leaf-list entry. The target node must + represent a new data resource."; + } + enum merge { + description + "The supplied value is merged with the target data + node."; + } + enum move { + description + "Move the target node. Reorder a user-ordered + list or leaf-list. The target node must represent + an existing data resource."; + } + enum replace { + description + "The supplied value is used to replace the target + data node."; + } + enum remove { + description + "Delete the target node if it currently exists."; + } + } + mandatory true; + description + "The datastore operation requested for the associated + edit entry"; + } + + leaf target { + type data-resource-identifier; + mandatory true; + description + "Identifies the target data resource for the edit + operation."; + } + + leaf point { + when "(../operation = 'insert' or " + + "../operation = 'move') and " + + "(../where = 'before' or ../where = 'after')" { + description + "Point leaf only applies for insert or move + operations, before or after an existing entry."; + } + type data-resource-identifier; + description + "The absolute URL path for the data node that is being + used as the insertion point or move point for the + target of this edit entry."; + } + + leaf where { + when "../operation = 'insert' or ../operation = 'move'" { + description + "Where leaf only applies for insert or move + operations."; + } + type enumeration { + enum before { + description + "Insert or move a data node before the data resource + identified by the 'point' parameter."; + } + enum after { + description + "Insert or move a data node after the data resource + identified by the 'point' parameter."; + } + enum first { + description + "Insert or move a data node so it becomes ordered + as the first entry."; + } + enum last { + description + "Insert or move a data node so it becomes ordered + as the last entry."; + } + + } + default last; + description + "Identifies where a data resource will be inserted or + moved. YANG only allows these operations for + list and leaf-list data nodes that are ordered-by + user."; + } + + anyxml value { + when "(../operation = 'create' or " + + "../operation = 'merge' " + + "or ../operation = 'replace' or " + + "../operation = 'insert')" { + description + "Value node only used for create, merge, + replace, and insert operations"; + } + description + "Value used for this edit operation."; + } + } + } + + } // grouping yang-patch + + + grouping yang-patch-status { + + description + "A grouping that contains a YANG container + representing the syntax and semantics of + YANG Patch status response message."; + + container yang-patch-status { + description + "A container representing the response message + sent by the server after a YANG Patch edit + request message has been processed."; + + leaf patch-id { + type string; + description + "The patch-id value used in the request"; + } + + choice global-status { + description + "Report global errors or complete success. + If there is no case selected then errors + are reported in the edit-status container."; + + case global-errors { + uses errors; + description + "This container will be present if global + errors unrelated to a specific edit occurred."; + } + leaf ok { + type empty; + description + "This leaf will be present if the request succeeded + and there are no errors reported in the edit-status + container."; + } + } + + container edit-status { + description + "This container will be present if there are + edit-specific status responses to report."; + + list edit { + key edit-id; + + description + "Represents a list of status responses, + corresponding to edits in the YANG Patch + request message. If an edit entry was + skipped or not reached by the server, + then this list will not contain a corresponding + entry for that edit."; + + leaf edit-id { + type string; + description + "Response status is for the edit list entry + with this edit-id value."; + } + choice edit-status-choice { + description + "A choice between different types of status + responses for each edit entry."; + leaf ok { + type empty; + description + "This edit entry was invoked without any + errors detected by the server associated + with this edit."; + } + leaf location { + type inet:uri; + description + "Contains the Location header value that would be + returned if this edit causes a new resource to be + created. If the edit identified by the same edit-id + value was successfully invoked and a new resource + was created, then this field will be returned + instead of 'ok'."; + } + case errors { + uses errors; + description + "The server detected errors associated with the + edit identified by the same edit-id value."; + } + } + } + } + } + } // grouping yang-patch-status + + + grouping errors { + + description + "A grouping that contains a YANG container + representing the syntax and semantics of a + YANG Patch errors report within a response message."; + + container errors { + config false; // needed so list error does not need a key + description + "Represents an error report returned by the server if + a request results in an error."; + + list error { + description + "An entry containing information about one + specific error that occurred while processing + a RESTCONF request."; + reference "RFC 6241, Section 4.3"; + + leaf error-type { + type enumeration { + enum transport { + description "The transport layer"; + } + enum rpc { + description "The rpc or notification layer"; + } + enum protocol { + description "The protocol operation layer"; + } + enum application { + description "The server application layer"; + } + } + mandatory true; + description + "The protocol layer where the error occurred."; + } + + leaf error-tag { + type string; + mandatory true; + description + "The enumerated error tag."; + } + + leaf error-app-tag { + type string; + description + "The application-specific error tag."; + } + + leaf error-path { + type data-resource-identifier; + description + "The target data resource identifier associated + with the error, if any."; + } + leaf error-message { + type string; + description + "A message describing the error."; + } + + container error-info { + description + "A container allowing additional information + to be included in the error report."; + // arbitrary anyxml content here + } + } + } + } // grouping errors + + + grouping restconf { + + description + "A grouping that contains a YANG container + representing the syntax and semantics of + the RESTCONF API resource."; + + container restconf { + description + "Conceptual container representing the + application/yang.api resource type."; + + container config { + description + "Container representing the application/yang.datastore + resource type. Represents the conceptual root of the + unified configuration datastore containing YANG data + nodes. The child nodes of this container are + configuration data resources (application/yang.data) + defined as top-level YANG data nodes from the modules + advertised by the server in /restconf/modules."; + } + + container operational { + description + "Container representing the application/yang.datastore + resource type. Represents the conceptual root of the + operational data supported by the server. The child + nodes of this container are operational data resources + (application/yang.data) defined as top-level + YANG data nodes from the modules advertised by + the server in /restconf/modules."; + } + + container modules { + description + "Contains a list of module description entries. + These modules are currently loaded into the server."; + + list module { + key "name revision"; + description + "Each entry represents one module currently + supported by the server."; + + leaf name { + type yang:yang-identifier; + description "The YANG module name."; + } + leaf revision { + type union { + type revision-identifier; + type string { length 0; } + } + description + "The YANG module revision date. An empty string is + used if no revision statement is present in the + YANG module."; + } + leaf namespace { + type inet:uri; + mandatory true; + description + "The XML namespace identifier for this module."; + } + leaf-list feature { + type yang:yang-identifier; + description + "List of YANG feature names from this module that are + supported by the server."; + } + leaf-list deviation { + type yang:yang-identifier; + description + "List of YANG deviation module names used by this + server to modify the conformance of the module + associated with this entry."; + } + } + } + + container operations { + description + "Container for all operation resources + (application/yang.operation), + + Each resource is represented as an empty leaf with the + name of the RPC operation from the YANG rpc statement. + + E.g.; + + POST /restconf/operations/show-log-errors + + leaf show-log-errors { + type empty; + } + "; + } + + container streams { + description + "Container representing the notification event streams + supported by the server."; + reference + "RFC 5277, Section 3.4, element."; + + list stream { + key name; + description + "Each entry describes an event stream supported by + the server."; + + leaf name { + type string; + description "The stream name"; + reference "RFC 5277, Section 3.4, element."; + } + + leaf description { + type string; + description "Description of stream content"; + reference + "RFC 5277, Section 3.4, element."; + } + + leaf replay-support { + type boolean; + description + "Indicates if replay buffer supported for this stream"; + reference + "RFC 5277, Section 3.4, element."; + } + + leaf replay-log-creation-time { + type yang:date-and-time; + description + "Indicates the time the replay log for this stream + was created."; + reference + "RFC 5277, Section 3.4, + element."; + } + + leaf events { + type empty; + description + "Represents the entry point for establishing + notification delivery via server sent events."; + } + } + } + + leaf version { + type enumeration { + enum "1.0" { + description + "Version 1.0 of the RESTCONF protocol."; + } + } + config false; + description + "Contains the RESTCONF protocol version."; + } + } + } // grouping restconf + + + grouping notification { + description + "Contains the notification message wrapper definition."; + + container notification { + description + "RESTCONF notification message wrapper."; + leaf event-time { + type yang:date-and-time; + mandatory true; + description + "The time the event was generated by the + event source."; + reference + "RFC 5277, section 4, element."; + } + + /* The YANG-specific notification container is encoded + * after the 'event-time' element. The format + * corresponds to the notificationContent element + * in RFC 5277, section 4. For example: + * + * module example-one { + * ... + * notification event1 { ... } + * + * } + * + * Encoded as element 'event1' in the namespace + * for module 'example-one'. + */ + } + } // grouping notification + + } \ No newline at end of file diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/modules/ietf-yang-types.yang b/opendaylight/md-sal/sal-rest-connector/src/test/resources/modules/ietf-yang-types.yang new file mode 100644 index 0000000000..07e50b3913 --- /dev/null +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/modules/ietf-yang-types.yang @@ -0,0 +1,417 @@ + module ietf-yang-types { + + namespace "urn:ietf:params:xml:ns:yang:ietf-yang-types"; + prefix "yang"; + + organization + "IETF NETMOD (NETCONF Data Modeling Language) Working Group"; + + contact + "WG Web: + WG List: + + WG Chair: David Partain + + + WG Chair: David Kessens + + + Editor: Juergen Schoenwaelder + "; + + description + "This module contains a collection of generally useful derived + YANG data types. + + Copyright (c) 2010 IETF Trust and the persons identified as + authors of the code. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, is permitted pursuant to, and subject to the license + terms contained in, the Simplified BSD License set forth in Section + 4.c of the IETF Trust's Legal Provisions Relating to IETF Documents + (http://trustee.ietf.org/license-info). + + This version of this YANG module is part of RFC 6021; see + the RFC itself for full legal notices."; + + revision 2010-09-24 { + description + "Initial revision."; + reference + "RFC 6021: Common YANG Data Types"; + } + + /*** collection of counter and gauge types ***/ + + typedef counter32 { + type uint32; + description + "The counter32 type represents a non-negative integer + that monotonically increases until it reaches a + maximum value of 2^32-1 (4294967295 decimal), when it + wraps around and starts increasing again from zero. + + Counters have no defined 'initial' value, and thus, a + single value of a counter has (in general) no information + content. Discontinuities in the monotonically increasing + value normally occur at re-initialization of the + management system, and at other times as specified in the + description of a schema node using this type. If such + other times can occur, for example, the creation of + a schema node of type counter32 at times other than + re-initialization, then a corresponding schema node + should be defined, with an appropriate type, to indicate + the last discontinuity. + + The counter32 type should not be used for configuration + schema nodes. A default statement SHOULD NOT be used in + combination with the type counter32. + + In the value set and its semantics, this type is equivalent + to the Counter32 type of the SMIv2."; + reference + "RFC 2578: Structure of Management Information Version 2 (SMIv2)"; + } + + typedef zero-based-counter32 { + type yang:counter32; + default "0"; + description + "The zero-based-counter32 type represents a counter32 + that has the defined 'initial' value zero. + + A schema node of this type will be set to zero (0) on creation + and will thereafter increase monotonically until it reaches + a maximum value of 2^32-1 (4294967295 decimal), when it + wraps around and starts increasing again from zero. + + Provided that an application discovers a new schema node + of this type within the minimum time to wrap, it can use the + 'initial' value as a delta. It is important for a management + station to be aware of this minimum time and the actual time + between polls, and to discard data if the actual time is too + long or there is no defined minimum time. + + In the value set and its semantics, this type is equivalent + to the ZeroBasedCounter32 textual convention of the SMIv2."; + reference + "RFC 4502: Remote Network Monitoring Management Information + Base Version 2"; + } + + typedef counter64 { + type uint64; + description + "The counter64 type represents a non-negative integer + that monotonically increases until it reaches a + maximum value of 2^64-1 (18446744073709551615 decimal), + when it wraps around and starts increasing again from zero. + + Counters have no defined 'initial' value, and thus, a + single value of a counter has (in general) no information + content. Discontinuities in the monotonically increasing + value normally occur at re-initialization of the + management system, and at other times as specified in the + description of a schema node using this type. If such + other times can occur, for example, the creation of + a schema node of type counter64 at times other than + re-initialization, then a corresponding schema node + should be defined, with an appropriate type, to indicate + the last discontinuity. + + The counter64 type should not be used for configuration + schema nodes. A default statement SHOULD NOT be used in + combination with the type counter64. + + In the value set and its semantics, this type is equivalent + to the Counter64 type of the SMIv2."; + reference + "RFC 2578: Structure of Management Information Version 2 (SMIv2)"; + } + + typedef zero-based-counter64 { + type yang:counter64; + default "0"; + description + "The zero-based-counter64 type represents a counter64 that + has the defined 'initial' value zero. + + A schema node of this type will be set to zero (0) on creation + and will thereafter increase monotonically until it reaches + a maximum value of 2^64-1 (18446744073709551615 decimal), + when it wraps around and starts increasing again from zero. + + Provided that an application discovers a new schema node + of this type within the minimum time to wrap, it can use the + 'initial' value as a delta. It is important for a management + station to be aware of this minimum time and the actual time + between polls, and to discard data if the actual time is too + long or there is no defined minimum time. + + In the value set and its semantics, this type is equivalent + to the ZeroBasedCounter64 textual convention of the SMIv2."; + reference + "RFC 2856: Textual Conventions for Additional High Capacity + Data Types"; + } + + typedef gauge32 { + type uint32; + description + "The gauge32 type represents a non-negative integer, which + may increase or decrease, but shall never exceed a maximum + value, nor fall below a minimum value. The maximum value + cannot be greater than 2^32-1 (4294967295 decimal), and + the minimum value cannot be smaller than 0. The value of + a gauge32 has its maximum value whenever the information + being modeled is greater than or equal to its maximum + value, and has its minimum value whenever the information + being modeled is smaller than or equal to its minimum value. + If the information being modeled subsequently decreases + below (increases above) the maximum (minimum) value, the + gauge32 also decreases (increases). + + In the value set and its semantics, this type is equivalent + to the Gauge32 type of the SMIv2."; + reference + "RFC 2578: Structure of Management Information Version 2 (SMIv2)"; + } + + typedef gauge64 { + type uint64; + description + "The gauge64 type represents a non-negative integer, which + may increase or decrease, but shall never exceed a maximum + value, nor fall below a minimum value. The maximum value + cannot be greater than 2^64-1 (18446744073709551615), and + the minimum value cannot be smaller than 0. The value of + a gauge64 has its maximum value whenever the information + being modeled is greater than or equal to its maximum + value, and has its minimum value whenever the information + being modeled is smaller than or equal to its minimum value. + If the information being modeled subsequently decreases + below (increases above) the maximum (minimum) value, the + gauge64 also decreases (increases). + + In the value set and its semantics, this type is equivalent + to the CounterBasedGauge64 SMIv2 textual convention defined + in RFC 2856"; + reference + "RFC 2856: Textual Conventions for Additional High Capacity + Data Types"; + } + + /*** collection of identifier related types ***/ + + typedef object-identifier { + type string { + pattern '(([0-1](\.[1-3]?[0-9]))|(2\.(0|([1-9]\d*))))' + + '(\.(0|([1-9]\d*)))*'; + } + description + "The object-identifier type represents administratively + assigned names in a registration-hierarchical-name tree. + + Values of this type are denoted as a sequence of numerical + non-negative sub-identifier values. Each sub-identifier + value MUST NOT exceed 2^32-1 (4294967295). Sub-identifiers + are separated by single dots and without any intermediate + whitespace. + + The ASN.1 standard restricts the value space of the first + sub-identifier to 0, 1, or 2. Furthermore, the value space + of the second sub-identifier is restricted to the range + 0 to 39 if the first sub-identifier is 0 or 1. Finally, + the ASN.1 standard requires that an object identifier + has always at least two sub-identifier. The pattern + captures these restrictions. + + Although the number of sub-identifiers is not limited, + module designers should realize that there may be + implementations that stick with the SMIv2 limit of 128 + sub-identifiers. + + This type is a superset of the SMIv2 OBJECT IDENTIFIER type + since it is not restricted to 128 sub-identifiers. Hence, + this type SHOULD NOT be used to represent the SMIv2 OBJECT + IDENTIFIER type, the object-identifier-128 type SHOULD be + used instead."; + reference + "ISO9834-1: Information technology -- Open Systems + Interconnection -- Procedures for the operation of OSI + Registration Authorities: General procedures and top + arcs of the ASN.1 Object Identifier tree"; + } + + + + + typedef object-identifier-128 { + type object-identifier { + pattern '\d*(\.\d*){1,127}'; + } + description + "This type represents object-identifiers restricted to 128 + sub-identifiers. + + In the value set and its semantics, this type is equivalent + to the OBJECT IDENTIFIER type of the SMIv2."; + reference + "RFC 2578: Structure of Management Information Version 2 (SMIv2)"; + } + + typedef yang-identifier { + type string { + length "1..max"; + pattern '[a-zA-Z_][a-zA-Z0-9\-_.]*'; + pattern '.|..|[^xX].*|.[^mM].*|..[^lL].*'; + } + description + "A YANG identifier string as defined by the 'identifier' + rule in Section 12 of RFC 6020. An identifier must + start with an alphabetic character or an underscore + followed by an arbitrary sequence of alphabetic or + numeric characters, underscores, hyphens, or dots. + + A YANG identifier MUST NOT start with any possible + combination of the lowercase or uppercase character + sequence 'xml'."; + reference + "RFC 6020: YANG - A Data Modeling Language for the Network + Configuration Protocol (NETCONF)"; + } + + /*** collection of date and time related types ***/ + + typedef date-and-time { + type string { + pattern '\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?' + + '(Z|[\+\-]\d{2}:\d{2})'; + } + description + "The date-and-time type is a profile of the ISO 8601 + standard for representation of dates and times using the + Gregorian calendar. The profile is defined by the + date-time production in Section 5.6 of RFC 3339. + + The date-and-time type is compatible with the dateTime XML + schema type with the following notable exceptions: + + (a) The date-and-time type does not allow negative years. + + (b) The date-and-time time-offset -00:00 indicates an unknown + time zone (see RFC 3339) while -00:00 and +00:00 and Z all + represent the same time zone in dateTime. + + (c) The canonical format (see below) of data-and-time values + differs from the canonical format used by the dateTime XML + schema type, which requires all times to be in UTC using the + time-offset 'Z'. + + This type is not equivalent to the DateAndTime textual + convention of the SMIv2 since RFC 3339 uses a different + separator between full-date and full-time and provides + higher resolution of time-secfrac. + + The canonical format for date-and-time values with a known time + zone uses a numeric time zone offset that is calculated using + the device's configured known offset to UTC time. A change of + the device's offset to UTC time will cause date-and-time values + to change accordingly. Such changes might happen periodically + in case a server follows automatically daylight saving time + (DST) time zone offset changes. The canonical format for + date-and-time values with an unknown time zone (usually referring + to the notion of local time) uses the time-offset -00:00."; + reference + "RFC 3339: Date and Time on the Internet: Timestamps + RFC 2579: Textual Conventions for SMIv2 + XSD-TYPES: XML Schema Part 2: Datatypes Second Edition"; + } + + typedef timeticks { + type uint32; + description + "The timeticks type represents a non-negative integer that + represents the time, modulo 2^32 (4294967296 decimal), in + hundredths of a second between two epochs. When a schema + node is defined that uses this type, the description of + the schema node identifies both of the reference epochs. + + In the value set and its semantics, this type is equivalent + to the TimeTicks type of the SMIv2."; + reference + "RFC 2578: Structure of Management Information Version 2 (SMIv2)"; + } + + typedef timestamp { + type yang:timeticks; + description + "The timestamp type represents the value of an associated + timeticks schema node at which a specific occurrence happened. + The specific occurrence must be defined in the description + of any schema node defined using this type. When the specific + occurrence occurred prior to the last time the associated + timeticks attribute was zero, then the timestamp value is + zero. Note that this requires all timestamp values to be + reset to zero when the value of the associated timeticks + attribute reaches 497+ days and wraps around to zero. + + The associated timeticks schema node must be specified + in the description of any schema node using this type. + + In the value set and its semantics, this type is equivalent + to the TimeStamp textual convention of the SMIv2."; + reference + "RFC 2579: Textual Conventions for SMIv2"; + } + + /*** collection of generic address types ***/ + + typedef phys-address { + type string { + pattern '([0-9a-fA-F]{2}(:[0-9a-fA-F]{2})*)?'; + } + description + "Represents media- or physical-level addresses represented + as a sequence octets, each octet represented by two hexadecimal + numbers. Octets are separated by colons. The canonical + representation uses lowercase characters. + + In the value set and its semantics, this type is equivalent + to the PhysAddress textual convention of the SMIv2."; + reference + "RFC 2579: Textual Conventions for SMIv2"; + } + + typedef mac-address { + type string { + pattern '[0-9a-fA-F]{2}(:[0-9a-fA-F]{2}){5}'; + } + description + "The mac-address type represents an IEEE 802 MAC address. + The canonical representation uses lowercase characters. + + In the value set and its semantics, this type is equivalent + to the MacAddress textual convention of the SMIv2."; + reference + "IEEE 802: IEEE Standard for Local and Metropolitan Area + Networks: Overview and Architecture + RFC 2579: Textual Conventions for SMIv2"; + } + + /*** collection of XML specific types ***/ + + typedef xpath1.0 { + type string; + description + "This type represents an XPATH 1.0 expression. + + When a schema node is defined that uses this type, the + description of the schema node MUST specify the XPath + context in which the XPath expression is evaluated."; + reference + "XPATH: XML Path Language (XPath) Version 1.0"; + } + + } diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/modules/module1.yang b/opendaylight/md-sal/sal-rest-connector/src/test/resources/modules/module1.yang new file mode 100644 index 0000000000..604fe9458c --- /dev/null +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/modules/module1.yang @@ -0,0 +1,12 @@ +module module1 { + namespace "module:1"; + prefix "mod1"; + revision "2014-01-01"; + + rpc dummy-rpc1-module1 { + } + + rpc dummy-rpc2-module1 { + } + +} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/modules/module2.yang b/opendaylight/md-sal/sal-rest-connector/src/test/resources/modules/module2.yang new file mode 100644 index 0000000000..7b359f3efb --- /dev/null +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/modules/module2.yang @@ -0,0 +1,11 @@ +module module2 { + namespace "module:2"; + prefix "mod2"; + revision "2014-01-02"; + + rpc dummy-rpc1-module2 { + } + + rpc dummy-rpc2-module2 { + } +} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/modules/module3.yang b/opendaylight/md-sal/sal-rest-connector/src/test/resources/modules/module3.yang new file mode 100644 index 0000000000..39bb690be0 --- /dev/null +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/modules/module3.yang @@ -0,0 +1,5 @@ +module module3 { + namespace "module:3"; + prefix "mod3"; + revision "2014-01-03"; +} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/modules/modules-behind-mount-point/module1-behind-mount-point.yang b/opendaylight/md-sal/sal-rest-connector/src/test/resources/modules/modules-behind-mount-point/module1-behind-mount-point.yang new file mode 100644 index 0000000000..e48184b4df --- /dev/null +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/modules/modules-behind-mount-point/module1-behind-mount-point.yang @@ -0,0 +1,10 @@ +module module1-behind-mount-point { + namespace "module:1:behind:mount:point"; + prefix "mod1bemopo"; + revision "2014-02-03"; + + rpc rpc-behind-module1 { + } + + +} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/modules/modules-behind-mount-point/module2-behind-mount-point.yang b/opendaylight/md-sal/sal-rest-connector/src/test/resources/modules/modules-behind-mount-point/module2-behind-mount-point.yang new file mode 100644 index 0000000000..89b8c02eba --- /dev/null +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/modules/modules-behind-mount-point/module2-behind-mount-point.yang @@ -0,0 +1,9 @@ +module module2-behind-mount-point { + namespace "module:2:behind:mount:point"; + prefix "mod2bemopo"; + revision "2014-02-04"; + + rpc rpc-behind-module2 { + } + +} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-restconf-broker/pom.xml b/opendaylight/md-sal/sal-restconf-broker/pom.xml index 8294c101e9..8159707d57 100644 --- a/opendaylight/md-sal/sal-restconf-broker/pom.xml +++ b/opendaylight/md-sal/sal-restconf-broker/pom.xml @@ -6,47 +6,87 @@ 1.1-SNAPSHOT sal-restconf-broker - jar + bundle scm:git:ssh://git.opendaylight.org:29418/controller.git scm:git:ssh://git.opendaylight.org:29418/controller.git https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL HEAD - - - - org.apache.felix - maven-bundle-plugin - true - - - - org.opendaylight.controller sal-binding-api - 1.1-SNAPSHOT + + + org.opendaylight.controller + sal-binding-util org.opendaylight.controller sal-remote - 1.1-SNAPSHOT + + + org.opendaylight.controller + sal-broker-impl + + + org.opendaylight.controller + sal-binding-config org.opendaylight.controller sal-core-api - 1.1-SNAPSHOT org.opendaylight.yangtools restconf-client-api ${yangtools.version} + + org.opendaylight.yangtools + restconf-client-impl + ${yangtools.version} + org.slf4j slf4j-api + + + + org.apache.felix + maven-bundle-plugin + true + + + ${project.groupId}.${project.artifactId} + + * + + + + + + org.codehaus.mojo + build-helper-maven-plugin + 1.8 + + + add-source + generate-sources + + add-source + + + + ${project.build.directory}/generated-sources/ + + + + + + + diff --git a/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/NotificationServiceImpl.java b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/NotificationServiceImpl.java deleted file mode 100644 index 76c98e3dda..0000000000 --- a/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/NotificationServiceImpl.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v1.0 which accompanies this distribution, - * and is available at http://www.eclipse.org/legal/epl-v10.html - */ -package org.opendaylight.controller.sal.binding.impl; - -import org.opendaylight.controller.sal.binding.api.NotificationListener; -import org.opendaylight.controller.sal.binding.api.NotificationService; -import org.opendaylight.yangtools.concepts.Registration; -import org.opendaylight.yangtools.yang.binding.Notification; - -public class NotificationServiceImpl implements NotificationService { - @Override - public void addNotificationListener(Class notificationType, NotificationListener listener) { - - } - - @Override - public void addNotificationListener(org.opendaylight.yangtools.yang.binding.NotificationListener listener) { - - } - - @Override - public void removeNotificationListener(org.opendaylight.yangtools.yang.binding.NotificationListener listener) { - - } - - @Override - public void removeNotificationListener(Class notificationType, NotificationListener listener) { - - } - - @Override - public Registration> registerNotificationListener(Class notificationType, NotificationListener listener) { - //TODO implementation using sal-remote - return null; - } - - @Override - public Registration registerNotificationListener(org.opendaylight.yangtools.yang.binding.NotificationListener listener) { - //TODO implementation using sal-remote - return null; - } -} diff --git a/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/DataBrokerServiceImpl.java b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/binding/impl/DataBrokerServiceImpl.java similarity index 88% rename from opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/DataBrokerServiceImpl.java rename to opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/binding/impl/DataBrokerServiceImpl.java index cbcdc99236..6fe56c87ed 100644 --- a/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/DataBrokerServiceImpl.java +++ b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/binding/impl/DataBrokerServiceImpl.java @@ -5,7 +5,7 @@ * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html */ -package org.opendaylight.controller.sal.binding.impl; +package org.opendaylight.controller.sal.restconf.binding.impl; import java.net.URL; import java.util.concurrent.Future; @@ -21,6 +21,8 @@ import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.DataRoot; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.opendaylight.yangtools.yang.common.RpcResult; +import org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMappingService; +import org.opendaylight.yangtools.yang.model.api.SchemaContextHolder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -30,8 +32,8 @@ public class DataBrokerServiceImpl implements DataBrokerService { private final RestconfClientContext restconfClientContext; private final RestconfClientContextFactory restconfClientContextFactory = null; - public DataBrokerServiceImpl(URL baseUrl) throws UnsupportedProtocolException { - this.restconfClientContext = restconfClientContextFactory.getRestconfClientContext(baseUrl); + public DataBrokerServiceImpl(URL baseUrl, BindingIndependentMappingService mappingService, SchemaContextHolder schemaContextHolder) throws UnsupportedProtocolException { + this.restconfClientContext = restconfClientContextFactory.getRestconfClientContext(baseUrl, mappingService, schemaContextHolder); } @Override public T getData(DataStoreIdentifier store, Class rootType) { diff --git a/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/SalRemoteServiceBroker.java b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/SalRemoteServiceBroker.java index 988bfd8ca5..74b23201e7 100644 --- a/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/SalRemoteServiceBroker.java +++ b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/SalRemoteServiceBroker.java @@ -8,25 +8,60 @@ package org.opendaylight.controller.sal.restconf.broker; -import org.opendaylight.controller.sal.core.api.Broker; -import org.opendaylight.controller.sal.core.api.Consumer; -import org.opendaylight.controller.sal.core.api.Provider; +import com.google.common.collect.ImmutableClassToInstanceMap; +import org.opendaylight.controller.md.sal.binding.util.BindingContextUtils; +import org.opendaylight.controller.sal.binding.api.BindingAwareBroker; +import org.opendaylight.controller.sal.binding.api.BindingAwareConsumer; +import org.opendaylight.controller.sal.binding.api.BindingAwareProvider; +import org.opendaylight.controller.sal.binding.api.BindingAwareService; +import org.opendaylight.controller.sal.binding.api.NotificationService; +import org.opendaylight.controller.sal.binding.api.RpcConsumerRegistry; +import org.opendaylight.controller.sal.binding.api.data.DataBrokerService; +import org.opendaylight.controller.sal.restconf.broker.impl.RemoteServicesFactory; +import org.opendaylight.yangtools.restconf.client.api.RestconfClientContext; import org.osgi.framework.BundleContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import static com.google.common.base.Preconditions.checkState; -public class SalRemoteServiceBroker implements Broker,AutoCloseable { +public class SalRemoteServiceBroker implements BindingAwareBroker,AutoCloseable { - @Override - public void close() throws Exception { + private static final Logger logger = LoggerFactory.getLogger(SalRemoteServiceBroker.class.toString()); + private ImmutableClassToInstanceMap supportedConsumerServices; + + private final String identifier; + + private RpcConsumerRegistry rpcBroker; + private NotificationService notificationBroker; + private DataBrokerService dataBroker; + private final RemoteServicesFactory servicesFactory; + + public SalRemoteServiceBroker(String instanceName,RestconfClientContext clientContext){ + this.identifier = instanceName; + this.servicesFactory = new RemoteServicesFactory(clientContext); } - @Override - public ConsumerSession registerConsumer(Consumer cons, BundleContext context) { - return null; + public void start() { + logger.info("Starting Binding Aware Broker: {}", identifier); + + supportedConsumerServices = ImmutableClassToInstanceMap. builder() + .put(NotificationService.class, servicesFactory.getNotificationService()) // + .put(DataBrokerService.class,servicesFactory.getDataBrokerService() ) // + .put(RpcConsumerRegistry.class,servicesFactory.getRpcConsumerRegistry() ).build(); } + public ProviderContext registerProvider(BindingAwareProvider provider, BundleContext ctx) { + throw new UnsupportedOperationException(); + } + @Override + public void close() throws Exception { + //TODO decide if serviceFactory should close clientContext or it has to be closed by consumer + } @Override - public ProviderSession registerProvider(Provider prov, BundleContext context) { - return null; + public ConsumerContext registerConsumer(BindingAwareConsumer consumer, BundleContext ctx) { + checkState(supportedConsumerServices != null, "Broker is not initialized."); + return BindingContextUtils.createConsumerContextAndInitialize(consumer, supportedConsumerServices); } + } diff --git a/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/event/RemoteDataChangeEvent.java b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/event/RemoteDataChangeEvent.java new file mode 100644 index 0000000000..9dfd262da2 --- /dev/null +++ b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/event/RemoteDataChangeEvent.java @@ -0,0 +1,144 @@ +/* + * 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.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,DataObject> { + private final Map, DataObject> createdConfig, createdOper, origConfig, origOper, updatedConfig, updatedOper; + private final Set> removedConfig, removedOper; + + public RemoteDataChangeEvent(DataChangedNotification dataChangedNotification) { + final Map, DataObject> createdConfig = new HashMap<>(); + final Map, DataObject> createdOper = new HashMap<>(); + final Map, DataObject> origConfig = new HashMap<>(); + final Map, DataObject> origOper = new HashMap<>(); + final Map, DataObject> updatedConfig = new HashMap<>(); + final Map, DataObject> updatedOper = new HashMap<>(); + final Set> removedConfig = new HashSet<>(); + final Set> 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 + public DataObject getOriginalConfigurationSubtree() { + throw new UnsupportedOperationException(); + } + + @Override + public DataObject getOriginalOperationalSubtree() { + throw new UnsupportedOperationException(); + } + + @Override + public DataObject getUpdatedConfigurationSubtree() { + throw new UnsupportedOperationException(); + } + + @Override + public DataObject getUpdatedOperationalSubtree() { + throw new UnsupportedOperationException(); + } + + @Override + public Map, DataObject> getCreatedOperationalData() { + return createdOper; + } + + @Override + public Map, DataObject> getCreatedConfigurationData() { + return createdConfig; + } + + @Override + public Map, DataObject> getUpdatedOperationalData() { + return updatedOper; + } + + @Override + public Map, DataObject> getUpdatedConfigurationData() { + return updatedConfig; + } + + @Override + public Set> getRemovedConfigurationData() { + return removedConfig; + } + + @Override + public Set> getRemovedOperationalData() { + return removedOper; + } + + @Override + public Map, DataObject> getOriginalConfigurationData() { + return origConfig; + } + + @Override + public Map, DataObject> getOriginalOperationalData() { + return origOper; + } +} diff --git a/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/impl/DataBrokerServiceImpl.java b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/impl/DataBrokerServiceImpl.java new file mode 100644 index 0000000000..e6659c2265 --- /dev/null +++ b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/impl/DataBrokerServiceImpl.java @@ -0,0 +1,168 @@ +/* + * 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.restconf.broker.impl; + +import com.google.common.base.Optional; +import java.util.Map; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import org.opendaylight.controller.sal.binding.api.data.DataBrokerService; +import org.opendaylight.controller.sal.binding.api.data.DataChangeListener; +import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction; +import org.opendaylight.controller.sal.common.DataStoreIdentifier; +import org.opendaylight.controller.sal.restconf.broker.listeners.RemoteDataChangeNotificationListener; +import org.opendaylight.controller.sal.restconf.broker.tools.RemoteStreamTools; +import org.opendaylight.controller.sal.restconf.broker.transactions.RemoteDataModificationTransaction; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.BeginTransactionOutput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.CreateDataChangeEventSubscriptionInputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.CreateDataChangeEventSubscriptionOutput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.SalRemoteService; +import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.opendaylight.yangtools.restconf.client.api.RestconfClientContext; +import org.opendaylight.yangtools.restconf.client.api.event.EventStreamInfo; +import org.opendaylight.yangtools.restconf.client.api.event.ListenableEventStreamContext; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.DataRoot; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.common.RpcResult; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class DataBrokerServiceImpl implements DataBrokerService { + + private static final Logger logger = LoggerFactory.getLogger(DataBrokerServiceImpl.class.toString()); + private RestconfClientContext restconfClientContext; + private SalRemoteService salRemoteService; + + public DataBrokerServiceImpl(RestconfClientContext restconfClientContext) { + this.restconfClientContext = restconfClientContext; + this.salRemoteService = this.restconfClientContext.getRpcServiceContext(SalRemoteService.class).getRpcService(); + } + @Override + public T getData(DataStoreIdentifier store, Class rootType) { + throw new UnsupportedOperationException("Deprecated"); + } + + @Override + public T getData(DataStoreIdentifier store, T filter) { + throw new UnsupportedOperationException("Deprecated"); + } + + @Override + public T getCandidateData(DataStoreIdentifier store, Class rootType) { + throw new UnsupportedOperationException("Deprecated"); + } + + @Override + public T getCandidateData(DataStoreIdentifier store, T filter) { + throw new UnsupportedOperationException("Deprecated"); + } + + @Override + public RpcResult editCandidateData(DataStoreIdentifier store, DataRoot changeSet) { + throw new UnsupportedOperationException("Deprecated"); + } + + @Override + public Future> commit(DataStoreIdentifier store) { + throw new UnsupportedOperationException("Deprecated"); + } + + @Override + public DataObject getData(InstanceIdentifier data) { + throw new UnsupportedOperationException("Deprecated"); + } + + @Override + public DataObject getConfigurationData(InstanceIdentifier data) { + throw new UnsupportedOperationException("Deprecated"); + } + + @Override + public DataModificationTransaction beginTransaction() { + Future> rpcResultFuture = this.salRemoteService.beginTransaction(); + //TODO finish yang model for proper remoteDataModificationTransaction setup + RemoteDataModificationTransaction remoteDataModificationTransaction = new RemoteDataModificationTransaction(); + return remoteDataModificationTransaction; + } + + @Override + public void registerChangeListener(InstanceIdentifier path, DataChangeListener changeListener) { + throw new UnsupportedOperationException("Deprecated"); + } + + @Override + public void unregisterChangeListener(InstanceIdentifier path, DataChangeListener changeListener) { + throw new UnsupportedOperationException("Deprecated"); + } + + @Override + public DataObject readConfigurationData(InstanceIdentifier path) { + try { + Optional optDataObject = (Optional) this.restconfClientContext.getConfigurationDatastore().readData(path).get(); + if (optDataObject.isPresent()){ + return optDataObject.get(); + } + } catch (InterruptedException e) { + logger.trace("Reading configuration data interrupted {}",e); + } catch (ExecutionException e) { + logger.trace("Reading configuration execution exception {}",e); + } + throw new IllegalStateException("No data to return."); + } + + @Override + public DataObject readOperationalData(InstanceIdentifier path) { + try { + Optional optDataObject = (Optional) this.restconfClientContext.getOperationalDatastore().readData(path).get(); + if (optDataObject.isPresent()){ + return optDataObject.get(); + } + } catch (InterruptedException e) { + logger.trace("Reading configuration data interrupted {}",e); + } catch (ExecutionException e) { + logger.trace("Reading configuration execution exception {}",e); + } + throw new IllegalStateException("No data to return."); + } + @Override + public ListenerRegistration registerDataChangeListener(InstanceIdentifier path, DataChangeListener listener) { + CreateDataChangeEventSubscriptionInputBuilder inputBuilder = new CreateDataChangeEventSubscriptionInputBuilder(); + Future> rpcResultFuture = salRemoteService.createDataChangeEventSubscription(inputBuilder.setPath(path).build()); + String streamName = ""; + try { + if (rpcResultFuture.get().isSuccessful()){ + streamName = rpcResultFuture.get().getResult().getStreamName(); + } + } catch (InterruptedException e) { + logger.trace("Interupted while getting rpc result due to {}",e); + } catch (ExecutionException e) { + logger.trace("Execution exception while getting rpc result due to {}",e); + } + final Map desiredEventStream = RemoteStreamTools.createEventStream(restconfClientContext,streamName); + ListenableEventStreamContext restConfListenableEventStreamContext = restconfClientContext.getEventStreamContext(desiredEventStream.get(streamName)); + RemoteDataChangeNotificationListener remoteDataChangeNotificationListener = new RemoteDataChangeNotificationListener(listener); + restConfListenableEventStreamContext.registerNotificationListener(remoteDataChangeNotificationListener); + return new SalRemoteDataListenerRegistration(listener); + } + + private class SalRemoteDataListenerRegistration implements ListenerRegistration { + private DataChangeListener dataChangeListener; + public SalRemoteDataListenerRegistration(DataChangeListener dataChangeListener){ + this.dataChangeListener = dataChangeListener; + } + @Override + public DataChangeListener getInstance() { + return this.dataChangeListener; + } + @Override + public void close() throws Exception { + //noop + } + } +} diff --git a/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/impl/NotificationServiceImpl.java b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/impl/NotificationServiceImpl.java new file mode 100644 index 0000000000..3272ce5670 --- /dev/null +++ b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/impl/NotificationServiceImpl.java @@ -0,0 +1,118 @@ +/* + * 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.restconf.broker.impl; + +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.controller.sal.restconf.broker.tools.RemoteStreamTools; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.QName; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.SalRemoteService; +import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.opendaylight.yangtools.concepts.Registration; +import org.opendaylight.yangtools.restconf.client.api.RestconfClientContext; +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 final SalRemoteService salRemoteService; + private final RestconfClientContext restconfClientContext; + + private final Multimap,NotificationListener> listeners; + private ExecutorService _executor; + + public NotificationServiceImpl(RestconfClientContext restconfClienetContext){ + this.restconfClientContext = restconfClienetContext; + this.salRemoteService = this.restconfClientContext.getRpcServiceContext(SalRemoteService.class).getRpcService(); + + HashMultimap,NotificationListener> _create = HashMultimap., NotificationListener>create(); + SetMultimap,NotificationListener> _synchronizedSetMultimap = Multimaps., NotificationListener>synchronizedSetMultimap(_create); + this.listeners = _synchronizedSetMultimap; + + } + public ExecutorService getExecutor() { + return this._executor; + } + + public void setExecutor(final ExecutorService executor) { + this._executor = executor; + } + + @Override + public void addNotificationListener(Class notificationType, NotificationListener listener) { + this.listeners.put(notificationType, listener); + } + + @Override + public void addNotificationListener(org.opendaylight.yangtools.yang.binding.NotificationListener listener) { + UnsupportedOperationException _unsupportedOperationException = new UnsupportedOperationException("Deprecated method. Use registerNotificationListener instead."); + throw _unsupportedOperationException; + } + + @Override + public void removeNotificationListener(org.opendaylight.yangtools.yang.binding.NotificationListener listener) { + UnsupportedOperationException _unsupportedOperationException = new UnsupportedOperationException( + "Deprecated method. Use RegisterNotificationListener returned value to close registration."); + throw _unsupportedOperationException; + } + + @Override + public void removeNotificationListener(Class notificationType, NotificationListener listener) { + this.listeners.remove(notificationType, listener); + } + + @Override + public Registration> registerNotificationListener(Class notificationType, NotificationListener listener) { + //TODO implementation using sal-remote + List notifications = new ArrayList(); + notifications.add(new QName(notificationType.toString())); + String notificationStreamName = RemoteStreamTools.createNotificationStream(salRemoteService, notifications); + final Map desiredEventStream = RemoteStreamTools.createEventStream(restconfClientContext, notificationStreamName); + RemoteNotificationListener remoteNotificationListener = new RemoteNotificationListener(listener); + ListenerRegistration listenerRegistration = restconfClientContext.getEventStreamContext(desiredEventStream.get(desiredEventStream.get(notificationStreamName))).registerNotificationListener(remoteNotificationListener); + return new SalNotificationRegistration(listenerRegistration); + } + + @Override + public Registration registerNotificationListener(org.opendaylight.yangtools.yang.binding.NotificationListener listener) { + //TODO implementation using sal-remote + String notificationStreamName = RemoteStreamTools.createNotificationStream(salRemoteService, null); + final Map desiredEventStream = RemoteStreamTools.createEventStream(restconfClientContext, notificationStreamName); + return restconfClientContext.getEventStreamContext(desiredEventStream.get(desiredEventStream.get(notificationStreamName))).registerNotificationListener(listener); + } + + private class SalNotificationRegistration implements Registration>{ + private final Registration registration; + + public SalNotificationRegistration(ListenerRegistration listenerRegistration){ + this.registration = listenerRegistration; + } + + @Override + public NotificationListener getInstance() { + return this.getInstance(); + } + + @Override + public void close() throws Exception { + this.registration.close(); + } + } + + +} diff --git a/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/impl/RemoteServicesFactory.java b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/impl/RemoteServicesFactory.java new file mode 100644 index 0000000000..65ecd8b70b --- /dev/null +++ b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/impl/RemoteServicesFactory.java @@ -0,0 +1,35 @@ +/* + * 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.restconf.broker.impl; + +import org.opendaylight.controller.sal.binding.api.NotificationService; +import org.opendaylight.controller.sal.binding.api.RpcConsumerRegistry; +import org.opendaylight.controller.sal.binding.api.data.DataBrokerService; +import org.opendaylight.yangtools.restconf.client.api.RestconfClientContext; + +public class RemoteServicesFactory { + + private final RestconfClientContext restconfClientContext; + + public RemoteServicesFactory(RestconfClientContext restconfClientContext){ + this.restconfClientContext = restconfClientContext; + } + + public DataBrokerService getDataBrokerService(){ + return new DataBrokerServiceImpl(this.restconfClientContext); + } + + public NotificationService getNotificationService(){ + return new NotificationServiceImpl(this.restconfClientContext); + } + + public RpcConsumerRegistry getRpcConsumerRegistry(){ + return new RpcConsumerRegistryImpl(this.restconfClientContext); + } + +} diff --git a/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/RpcConsumerRegistryImpl.java b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/impl/RpcConsumerRegistryImpl.java similarity index 58% rename from opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/RpcConsumerRegistryImpl.java rename to opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/impl/RpcConsumerRegistryImpl.java index e6a67ee8eb..82342ace26 100644 --- a/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/RpcConsumerRegistryImpl.java +++ b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/impl/RpcConsumerRegistryImpl.java @@ -5,15 +5,21 @@ * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html */ -package org.opendaylight.controller.sal.binding.impl; +package org.opendaylight.controller.sal.restconf.broker.impl; import org.opendaylight.controller.sal.binding.api.RpcConsumerRegistry; +import org.opendaylight.yangtools.restconf.client.api.RestconfClientContext; import org.opendaylight.yangtools.yang.binding.RpcService; public class RpcConsumerRegistryImpl implements RpcConsumerRegistry { + + private RestconfClientContext restconfClientContext; + + public RpcConsumerRegistryImpl(RestconfClientContext restconfClientContext){ + this.restconfClientContext = restconfClientContext; + } @Override public T getRpcService(Class module) { - //TODO implementation using restconf-client - return null; + return restconfClientContext.getRpcServiceContext(module).getRpcService(); } } diff --git a/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/listeners/RemoteDataChangeNotificationListener.java b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/listeners/RemoteDataChangeNotificationListener.java new file mode 100644 index 0000000000..df72ac8ce2 --- /dev/null +++ b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/listeners/RemoteDataChangeNotificationListener.java @@ -0,0 +1,27 @@ +/* + * 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.restconf.broker.listeners; + +import org.opendaylight.controller.sal.binding.api.data.DataChangeListener; +import org.opendaylight.controller.sal.restconf.broker.event.RemoteDataChangeEvent; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.DataChangedNotification; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.SalRemoteListener; + +public class RemoteDataChangeNotificationListener implements SalRemoteListener { + + + private final DataChangeListener dataChangeListener; + + public RemoteDataChangeNotificationListener(DataChangeListener dataChangeListener){ + this.dataChangeListener = dataChangeListener; + } + @Override + public void onDataChangedNotification(DataChangedNotification notification) { + this.dataChangeListener.onDataChanged(new RemoteDataChangeEvent(notification)); + } +} diff --git a/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/listeners/RemoteNotificationListener.java b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/listeners/RemoteNotificationListener.java new file mode 100644 index 0000000000..895a5030e9 --- /dev/null +++ b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/listeners/RemoteNotificationListener.java @@ -0,0 +1,23 @@ +/* + * 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.restconf.broker.listeners; + +import org.opendaylight.controller.sal.binding.api.NotificationListener; + +public class RemoteNotificationListener implements org.opendaylight.yangtools.yang.binding.NotificationListener { + + org.opendaylight.controller.sal.binding.api.NotificationListener listener; + + public RemoteNotificationListener(NotificationListener listener){ + this.listener = listener; + } + public NotificationListener getListener(){ + return this.listener; + } + +} diff --git a/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/listeners/SalNotificationListener.java b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/listeners/SalNotificationListener.java new file mode 100644 index 0000000000..16ca0aee93 --- /dev/null +++ b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/listeners/SalNotificationListener.java @@ -0,0 +1,24 @@ +/* + * 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.restconf.broker.listeners; + +import org.opendaylight.controller.sal.binding.api.NotificationListener; +import org.opendaylight.yangtools.yang.binding.Notification; + + +public class SalNotificationListener implements NotificationListener { + private NotificationListener notificationListener; + + public SalNotificationListener( NotificationListener notificationListener){ + this.notificationListener = notificationListener; + } + @Override + public void onNotification(Notification notification) { + this.notificationListener.onNotification(notification); + } +} diff --git a/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/tools/RemoteStreamTools.java b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/tools/RemoteStreamTools.java new file mode 100644 index 0000000000..726f7f0649 --- /dev/null +++ b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/tools/RemoteStreamTools.java @@ -0,0 +1,71 @@ +/* + * 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.restconf.broker.tools; + +import com.google.common.util.concurrent.ListenableFuture; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.CreateNotificationStreamInputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.CreateNotificationStreamOutput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.QName; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.SalRemoteService; +import org.opendaylight.yangtools.restconf.client.api.RestconfClientContext; +import org.opendaylight.yangtools.restconf.client.api.event.EventStreamInfo; +import org.opendaylight.yangtools.yang.common.RpcResult; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class RemoteStreamTools { + private static final Logger logger = LoggerFactory.getLogger(RemoteStreamTools.class.toString()); + + public static String createNotificationStream(SalRemoteService salRemoteService,List notifications){ + CreateNotificationStreamInputBuilder notificationStreamInputBuilder = new CreateNotificationStreamInputBuilder(); + + if (null == notifications){ + notificationStreamInputBuilder.setNotifications(notifications); + } + + Future> notificationStream = salRemoteService.createNotificationStream(notificationStreamInputBuilder.build()); + + String nofiticationStreamIdentifier = ""; + try { + if (notificationStream.get().isSuccessful()){ + nofiticationStreamIdentifier = notificationStream.get().getResult().getNotificationStreamIdentifier(); + } + } catch (InterruptedException e) { + logger.trace("Interrupted while resolving notification stream identifier due to {}",e); + } catch (ExecutionException e) { + logger.trace("Execution exception while resolving notification stream identifier due to {}",e); + } + return nofiticationStreamIdentifier; + } + + public static Map createEventStream(RestconfClientContext restconfClientContext, String desiredStreamName){ + ListenableFuture> availableEventStreams = restconfClientContext.getAvailableEventStreams(); + final Map desiredEventStream = new HashMap(); + + try { + Iterator it = availableEventStreams.get().iterator(); + while (it.hasNext()){ + if (it.next().getIdentifier().equals(desiredStreamName)){ + desiredEventStream.put(desiredStreamName,it.next()); + } + } + } catch (InterruptedException e) { + logger.trace("Resolving of event stream interrupted due to {}",e); + } catch (ExecutionException e) { + logger.trace("Resolving of event stream failed due to {}",e); + } + return desiredEventStream; + } +} diff --git a/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/transactions/RemoteDataModificationTransaction.java b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/transactions/RemoteDataModificationTransaction.java new file mode 100644 index 0000000000..7f9cc8f6c4 --- /dev/null +++ b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/transactions/RemoteDataModificationTransaction.java @@ -0,0 +1,122 @@ +/* + * 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.restconf.broker.transactions; + +import java.util.Map; +import java.util.Set; +import java.util.concurrent.Future; +import org.opendaylight.controller.md.sal.common.api.TransactionStatus; +import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction; +import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.common.RpcResult; + +public class RemoteDataModificationTransaction implements DataModificationTransaction { + //TODO implement this + + @Override + public Object getIdentifier() { + return null; + } + + @Override + public TransactionStatus getStatus() { + return null; + } + + @Override + public void putRuntimeData(InstanceIdentifier path, DataObject data) { + + } + + @Override + public void putOperationalData(InstanceIdentifier path, DataObject data) { + + } + + @Override + public void putConfigurationData(InstanceIdentifier path, DataObject data) { + + } + + @Override + public void removeRuntimeData(InstanceIdentifier path) { + + } + + @Override + public void removeOperationalData(InstanceIdentifier path) { + + } + + @Override + public void removeConfigurationData(InstanceIdentifier path) { + + } + + @Override + public Future> commit() { + return null; + } + + @Override + public ListenerRegistration registerListener(DataTransactionListener listener) { + return null; + } + + @Override + public Map, DataObject> getCreatedOperationalData() { + return null; + } + + @Override + public Map, DataObject> getCreatedConfigurationData() { + return null; + } + + @Override + public Map, DataObject> getUpdatedOperationalData() { + return null; + } + + @Override + public Map, DataObject> getUpdatedConfigurationData() { + return null; + } + + @Override + public Set> getRemovedConfigurationData() { + return null; + } + + @Override + public Set> getRemovedOperationalData() { + return null; + } + + @Override + public Map, DataObject> getOriginalConfigurationData() { + return null; + } + + @Override + public Map, DataObject> getOriginalOperationalData() { + return null; + } + + @Override + public DataObject readOperationalData(InstanceIdentifier path) { + return null; + } + + @Override + public DataObject readConfigurationData(InstanceIdentifier path) { + return null; + } +} diff --git a/opendaylight/md-sal/sal-restconf-broker/src/test/java/org/opendaylight/controller/sal/binding/impl/test/DataBrokerImplTest.java b/opendaylight/md-sal/sal-restconf-broker/src/test/java/org/opendaylight/controller/sal/binding/impl/test/DataBrokerImplTest.java new file mode 100644 index 0000000000..eafc47d620 --- /dev/null +++ b/opendaylight/md-sal/sal-restconf-broker/src/test/java/org/opendaylight/controller/sal/binding/impl/test/DataBrokerImplTest.java @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.controller.sal.binding.impl.test; + +public class DataBrokerImplTest { + + public static void main(String[] args){ + + } +} diff --git a/opendaylight/md-sal/sal-restconf-broker/src/test/java/org/opendaylight/controller/sal/binding/impl/test/NotificationServiceImplTest.java b/opendaylight/md-sal/sal-restconf-broker/src/test/java/org/opendaylight/controller/sal/binding/impl/test/NotificationServiceImplTest.java new file mode 100644 index 0000000000..a91b06ee76 --- /dev/null +++ b/opendaylight/md-sal/sal-restconf-broker/src/test/java/org/opendaylight/controller/sal/binding/impl/test/NotificationServiceImplTest.java @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.controller.sal.binding.impl.test; + +public class NotificationServiceImplTest { + + public static void main(String[] args){ + + } +} diff --git a/opendaylight/md-sal/samples/toaster-consumer/src/main/java/org/opendaylight/controller/sample/toaster/provider/impl/ToastConsumerImpl.java b/opendaylight/md-sal/samples/toaster-consumer/src/main/java/org/opendaylight/controller/sample/toaster/provider/impl/ToastConsumerImpl.java index fde60d64ce..87e5787ef5 100644 --- a/opendaylight/md-sal/samples/toaster-consumer/src/main/java/org/opendaylight/controller/sample/toaster/provider/impl/ToastConsumerImpl.java +++ b/opendaylight/md-sal/samples/toaster-consumer/src/main/java/org/opendaylight/controller/sample/toaster/provider/impl/ToastConsumerImpl.java @@ -11,18 +11,14 @@ import java.util.Hashtable; import java.util.concurrent.ExecutionException; import org.opendaylight.controller.sal.binding.api.AbstractBindingAwareConsumer; +import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ConsumerContext; import org.opendaylight.controller.sal.binding.api.BindingAwareConsumer; import org.opendaylight.controller.sal.binding.api.NotificationListener; import org.opendaylight.controller.sal.binding.api.NotificationService; -import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ConsumerContext; -import org.opendaylight.controller.sal.binding.api.data.DataBrokerService; -import org.opendaylight.controller.sal.common.GlobalDataStore; import org.opendaylight.controller.sample.toaster.provider.api.ToastConsumer; import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.MakeToastInputBuilder; import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToastDone; import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToastType; -import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.Toaster; -import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToasterData; import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToasterService; import org.opendaylight.yangtools.yang.common.RpcResult; import org.osgi.framework.BundleActivator; @@ -71,7 +67,7 @@ public class ToastConsumerImpl extends AbstractBindingAwareConsumer implements B public void onSessionInitialized(ConsumerContext session) { this.session = session; NotificationService notificationService = session.getSALService(NotificationService.class); - notificationService.addNotificationListener(ToastDone.class, this); + notificationService.registerNotificationListener(ToastDone.class, this); } @Override diff --git a/opendaylight/md-sal/samples/toaster-provider/src/main/java/org/opendaylight/controller/sample/toaster/provider/ToasterProvider.java b/opendaylight/md-sal/samples/toaster-provider/src/main/java/org/opendaylight/controller/sample/toaster/provider/ToasterProvider.java index 5ba67474b3..ae482ed978 100644 --- a/opendaylight/md-sal/samples/toaster-provider/src/main/java/org/opendaylight/controller/sample/toaster/provider/ToasterProvider.java +++ b/opendaylight/md-sal/samples/toaster-provider/src/main/java/org/opendaylight/controller/sample/toaster/provider/ToasterProvider.java @@ -11,16 +11,10 @@ import java.util.Collection; import java.util.Collections; import org.opendaylight.controller.sal.binding.api.AbstractBindingAwareProvider; -import org.opendaylight.controller.sal.binding.api.BindingAwareBroker; -import org.opendaylight.controller.sal.binding.api.BindingAwareProvider; -import org.opendaylight.controller.sal.binding.api.NotificationProviderService; -import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ConsumerContext; import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext; +import org.opendaylight.controller.sal.binding.api.NotificationProviderService; import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToasterService; import org.opendaylight.yangtools.yang.binding.RpcService; -import org.osgi.framework.BundleActivator; -import org.osgi.framework.BundleContext; -import org.osgi.framework.ServiceReference; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -28,7 +22,7 @@ public class ToasterProvider extends AbstractBindingAwareProvider { private static final Logger log = LoggerFactory.getLogger(ToasterProvider.class); private ProviderContext providerContext; - private OpendaylightToaster toaster; + private final OpendaylightToaster toaster; public ToasterProvider() { toaster = new OpendaylightToaster(); diff --git a/opendaylight/md-sal/statistics-manager/pom.xml b/opendaylight/md-sal/statistics-manager/pom.xml index 0f90ecac60..5c3fc2329a 100644 --- a/opendaylight/md-sal/statistics-manager/pom.xml +++ b/opendaylight/md-sal/statistics-manager/pom.xml @@ -39,6 +39,17 @@ org.eclipse.xtend org.eclipse.xtend.lib + + + junit + junit + + + org.slf4j + slf4j-log4j12 + ${slf4j.version} + test + diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/AbstractListeningStatsTracker.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/AbstractListeningStatsTracker.java new file mode 100644 index 0000000000..4a58579b13 --- /dev/null +++ b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/AbstractListeningStatsTracker.java @@ -0,0 +1,48 @@ +/* + * 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 extends AbstractStatsTracker 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; + } + } +} diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/AbstractStatsTracker.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/AbstractStatsTracker.java new file mode 100644 index 0000000000..c29b6a7730 --- /dev/null +++ b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/AbstractStatsTracker.java @@ -0,0 +1,115 @@ +/* + * 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 { + private static final Logger logger = LoggerFactory.getLogger(AbstractStatsTracker.class); + private final FutureCallback> callback = + new FutureCallback>() { + @Override + public void onSuccess(RpcResult 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 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 getNodeIdentifierBuilder() { + return InstanceIdentifier.builder(getNodeIdentifier()); + } + + protected final NodeRef getNodeRef() { + return context.getNodeRef(); + } + + protected final InstanceIdentifier getNodeIdentifier() { + return context.getNodeIdentifier(); + } + + protected final void requestHelper(Future> 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 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> it = trackedItems.entrySet().iterator();it.hasNext();){ + Entry e = it.next(); + if (now > e.getValue()) { + cleanupSingleStat(trans, e.getKey()); + it.remove(); + } + } + } +} diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowCapableContext.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowCapableContext.java new file mode 100644 index 0000000000..520b344199 --- /dev/null +++ b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowCapableContext.java @@ -0,0 +1,27 @@ +/* + * 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 getNodeIdentifier(); + NodeRef getNodeRef(); + DataModificationTransaction startDataModification(); + void registerTransaction(TransactionId id); + void registerTableTransaction(TransactionId id, Short tableId); +} diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowCapableTracker.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowCapableTracker.java new file mode 100644 index 0000000000..bb1544c57a --- /dev/null +++ b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowCapableTracker.java @@ -0,0 +1,111 @@ +/* + * 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 root; + private final StatisticsProvider stats; + + private final Predicate> filterIdentifiers = new Predicate>() { + @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 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, 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 removedNodes = + Collections2.filter(Collections2.transform( + Sets.filter(change.getRemovedOperationalData(), filterIdentifiers), + new Function, 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 addedNodes = + Collections2.filter(Collections2.transform( + Sets.filter(change.getCreatedOperationalData().keySet(), filterIdentifiers), + new Function, 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); + } +} diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowComparator.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowComparator.java new file mode 100644 index 0000000000..af61db1a80 --- /dev/null +++ b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowComparator.java @@ -0,0 +1,317 @@ +/* + * 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.net.Inet4Address; +import java.net.InetAddress; +import java.net.UnknownHostException; + +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Match; +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Layer3Match; +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv4Match; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.annotations.VisibleForTesting; + +/** + * Utility class for comparing flows. + */ +final class FlowComparator { + private final static Logger logger = LoggerFactory.getLogger(FlowComparator.class); + + private FlowComparator() { + + } + + public static boolean flowEquals(Flow statsFlow, Flow storedFlow) { + if (statsFlow.getClass() != storedFlow.getClass()) { + return false; + } + if (statsFlow.getContainerName()== null) { + if (storedFlow.getContainerName()!= null) { + return false; + } + } else if(!statsFlow.getContainerName().equals(storedFlow.getContainerName())) { + return false; + } + if (statsFlow.getMatch()== null) { + if (storedFlow.getMatch() != null) { + return false; + } + } //else if(!statsFlow.getMatch().equals(storedFlow.getMatch())) { + else if(!matchEquals(statsFlow.getMatch(), storedFlow.getMatch())) { + return false; + } + if (storedFlow.getPriority() == null) { + if (statsFlow.getPriority() != null && statsFlow.getPriority()!= 0x8000) { + return false; + } + } else if(!statsFlow.getPriority().equals(storedFlow.getPriority())) { + return false; + } + if (statsFlow.getTableId() == null) { + if (storedFlow.getTableId() != null) { + return false; + } + } else if(!statsFlow.getTableId().equals(storedFlow.getTableId())) { + return false; + } + return true; + } + + /** + * Explicit equals method to compare the 'match' for flows stored in the data-stores and flow fetched from the switch. + * Flow installation process has three steps + * 1) Store flow in config data store + * 2) and send it to plugin for installation + * 3) Flow gets installed in switch + * + * The flow user wants to install and what finally gets installed in switch can be slightly different. + * E.g, If user installs flow with src/dst ip=10.0.0.1/24, when it get installed in the switch + * src/dst ip will be changes to 10.0.0.0/24 because of netmask of 24. When statistics manager fetch + * stats it gets 10.0.0.0/24 rather then 10.0.0.1/24. Custom match takes care of by using masked ip + * while comparing two ip addresses. + * + * Sometimes when user don't provide few values that is required by flow installation request, like + * priority,hard timeout, idle timeout, cookies etc, plugin usages default values before sending + * request to the switch. So when statistics manager gets flow statistics, it gets the default value. + * But the flow stored in config data store don't have those defaults value. I included those checks + * in the customer flow/match equal function. + * + * + * @param statsFlow + * @param storedFlow + * @return + */ + public static boolean matchEquals(Match statsFlow, Match storedFlow) { + if (statsFlow == storedFlow) { + return true; + } + if (storedFlow.getClass() != statsFlow.getClass()) { + return false; + } + if (storedFlow.getEthernetMatch() == null) { + if (statsFlow.getEthernetMatch() != null) { + return false; + } + } else if(!storedFlow.getEthernetMatch().equals(statsFlow.getEthernetMatch())) { + return false; + } + if (storedFlow.getIcmpv4Match()== null) { + if (statsFlow.getIcmpv4Match() != null) { + return false; + } + } else if(!storedFlow.getIcmpv4Match().equals(statsFlow.getIcmpv4Match())) { + return false; + } + if (storedFlow.getIcmpv6Match() == null) { + if (statsFlow.getIcmpv6Match() != null) { + return false; + } + } else if(!storedFlow.getIcmpv6Match().equals(statsFlow.getIcmpv6Match())) { + return false; + } + if (storedFlow.getInPhyPort() == null) { + if (statsFlow.getInPhyPort() != null) { + return false; + } + } else if(!storedFlow.getInPhyPort().equals(statsFlow.getInPhyPort())) { + return false; + } + if (storedFlow.getInPort()== null) { + if (statsFlow.getInPort() != null) { + return false; + } + } else if(!storedFlow.getInPort().equals(statsFlow.getInPort())) { + return false; + } + if (storedFlow.getIpMatch()== null) { + if (statsFlow.getIpMatch() != null) { + return false; + } + } else if(!storedFlow.getIpMatch().equals(statsFlow.getIpMatch())) { + return false; + } + if (storedFlow.getLayer3Match()== null) { + if (statsFlow.getLayer3Match() != null) { + return false; + } + } else if(!layer3MatchEquals(statsFlow.getLayer3Match(),storedFlow.getLayer3Match())) { + return false; + } + if (storedFlow.getLayer4Match()== null) { + if (statsFlow.getLayer4Match() != null) { + return false; + } + } else if(!storedFlow.getLayer4Match().equals(statsFlow.getLayer4Match())) { + return false; + } + if (storedFlow.getMetadata() == null) { + if (statsFlow.getMetadata() != null) { + return false; + } + } else if(!storedFlow.getMetadata().equals(statsFlow.getMetadata())) { + return false; + } + if (storedFlow.getProtocolMatchFields() == null) { + if (statsFlow.getProtocolMatchFields() != null) { + return false; + } + } else if(!storedFlow.getProtocolMatchFields().equals(statsFlow.getProtocolMatchFields())) { + return false; + } + if (storedFlow.getTunnel()== null) { + if (statsFlow.getTunnel() != null) { + return false; + } + } else if(!storedFlow.getTunnel().equals(statsFlow.getTunnel())) { + return false; + } + if (storedFlow.getVlanMatch()== null) { + if (statsFlow.getVlanMatch() != null) { + return false; + } + } else if(!storedFlow.getVlanMatch().equals(statsFlow.getVlanMatch())) { + return false; + } + return true; + } + + @VisibleForTesting + static boolean layer3MatchEquals(Layer3Match statsLayer3Match, Layer3Match storedLayer3Match){ + boolean verdict = true; + if(statsLayer3Match instanceof Ipv4Match && storedLayer3Match instanceof Ipv4Match){ + Ipv4Match statsIpv4Match = (Ipv4Match)statsLayer3Match; + Ipv4Match storedIpv4Match = (Ipv4Match)storedLayer3Match; + + if (verdict) { + verdict = compareNullSafe( + storedIpv4Match.getIpv4Destination(), statsIpv4Match.getIpv4Destination()); + } + if (verdict) { + verdict = compareNullSafe( + statsIpv4Match.getIpv4Source(), storedIpv4Match.getIpv4Source()); + } + } else { + Boolean nullCheckOut = checkNullValues(storedLayer3Match, statsLayer3Match); + if (nullCheckOut != null) { + verdict = nullCheckOut; + } else { + verdict = storedLayer3Match.equals(statsLayer3Match); + } + } + + return verdict; + } + + private static boolean compareNullSafe(Ipv4Prefix statsIpv4, Ipv4Prefix storedIpv4) { + boolean verdict = true; + Boolean checkDestNullValuesOut = checkNullValues(storedIpv4, statsIpv4); + if (checkDestNullValuesOut != null) { + verdict = checkDestNullValuesOut; + } else if(!IpAddressEquals(statsIpv4, storedIpv4)){ + verdict = false; + } + + return verdict; + } + + private static Boolean checkNullValues(Object v1, Object v2) { + Boolean verdict = null; + if (v1 == null && v2 != null) { + verdict = Boolean.FALSE; + } else if (v1 != null && v2 == null) { + verdict = Boolean.FALSE; + } else if (v1 == null && v2 == null) { + verdict = Boolean.TRUE; + } + + return verdict; + } + + /** + * TODO: why don't we use the default Ipv4Prefix.equals()? + * + * @param statsIpAddress + * @param storedIpAddress + * @return true if IPv4prefixes equals + */ + private static boolean IpAddressEquals(Ipv4Prefix statsIpAddress, Ipv4Prefix storedIpAddress) { + IntegerIpAddress statsIpAddressInt = StrIpToIntIp(statsIpAddress.getValue()); + IntegerIpAddress storedIpAddressInt = StrIpToIntIp(storedIpAddress.getValue()); + + if(IpAndMaskBasedMatch(statsIpAddressInt,storedIpAddressInt)){ + return true; + } + if(IpBasedMatch(statsIpAddressInt,storedIpAddressInt)){ + return true; + } + return false; + } + + private static boolean IpAndMaskBasedMatch(IntegerIpAddress statsIpAddressInt,IntegerIpAddress storedIpAddressInt){ + return ((statsIpAddressInt.getIp() & statsIpAddressInt.getMask()) == (storedIpAddressInt.getIp() & storedIpAddressInt.getMask())); + } + + private static boolean IpBasedMatch(IntegerIpAddress statsIpAddressInt,IntegerIpAddress storedIpAddressInt){ + return (statsIpAddressInt.getIp() == storedIpAddressInt.getIp()); + } + + /** + * Method return integer version of ip address. Converted int will be mask if + * mask specified + */ + private static IntegerIpAddress StrIpToIntIp(String ipAddresss){ + + String[] parts = ipAddresss.split("/"); + String ip = parts[0]; + int prefix; + + if (parts.length < 2) { + prefix = 32; + } else { + prefix = Integer.parseInt(parts[1]); + } + + IntegerIpAddress integerIpAddress = null; + try { + Inet4Address addr = (Inet4Address) InetAddress.getByName(ip); + byte[] addrBytes = addr.getAddress(); + int ipInt = ((addrBytes[0] & 0xFF) << 24) | + ((addrBytes[1] & 0xFF) << 16) | + ((addrBytes[2] & 0xFF) << 8) | + ((addrBytes[3] & 0xFF) << 0); + + int mask = 0xffffffff << 32 - prefix; + + integerIpAddress = new IntegerIpAddress(ipInt, mask); + } catch (UnknownHostException e){ + logger.error("Failed to determine host IP address by name: {}", e.getMessage(), e); + } + + return integerIpAddress; + } + + private static class IntegerIpAddress{ + int ip; + int mask; + public IntegerIpAddress(int ip, int mask) { + this.ip = ip; + this.mask = mask; + } + public int getIp() { + return ip; + } + public int getMask() { + return mask; + } + } +} diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowStatsEntry.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowStatsEntry.java new file mode 100644 index 0000000000..b5b39d94d2 --- /dev/null +++ b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowStatsEntry.java @@ -0,0 +1,59 @@ +/* + * 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; + } +} diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowStatsTracker.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowStatsTracker.java new file mode 100644 index 0000000000..90ddc28acd --- /dev/null +++ b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowStatsTracker.java @@ -0,0 +1,272 @@ +/* + * 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 { + 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 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 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 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 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, DataObject> change) { + for (Entry, 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 = (InstanceIdentifier)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); + } +} diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowTableStatsTracker.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowTableStatsTracker.java new file mode 100644 index 0000000000..3fe68c111a --- /dev/null +++ b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowTableStatsTracker.java @@ -0,0 +1,72 @@ +/* + * 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 { + private final Set privateTables = new ConcurrentSkipListSet<>(); + private final Set tables = Collections.unmodifiableSet(privateTables); + private final OpendaylightFlowTableStatisticsService flowTableStatsService; + + FlowTableStatsTracker(OpendaylightFlowTableStatisticsService flowTableStatsService, final FlowCapableContext context, long lifetimeNanos) { + super(context, lifetimeNanos); + this.flowTableStatsService = flowTableStatsService; + } + + Set 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
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())); + } + } +} diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/GroupDescStatsTracker.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/GroupDescStatsTracker.java new file mode 100644 index 0000000000..8aebd6b249 --- /dev/null +++ b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/GroupDescStatsTracker.java @@ -0,0 +1,116 @@ +/* + * 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 { + 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 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 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, 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 = (InstanceIdentifier)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); + } +} diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/GroupStatsTracker.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/GroupStatsTracker.java new file mode 100644 index 0000000000..1af8e4e9f1 --- /dev/null +++ b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/GroupStatsTracker.java @@ -0,0 +1,107 @@ +/* + * 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 { + 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 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 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, DataObject> change) { + final DataModificationTransaction trans = startTransaction(); + for (InstanceIdentifier key : change.getRemovedConfigurationData()) { + if (Group.class.equals(key.getTargetType())) { + @SuppressWarnings("unchecked") + InstanceIdentifier group = (InstanceIdentifier)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); + } +} diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/MeterConfigStatsTracker.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/MeterConfigStatsTracker.java new file mode 100644 index 0000000000..4b95925705 --- /dev/null +++ b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/MeterConfigStatsTracker.java @@ -0,0 +1,111 @@ +/* + * 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 { + 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 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 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, DataObject> change) { + final DataModificationTransaction trans = startTransaction(); + + for (InstanceIdentifier key : change.getRemovedConfigurationData()) { + if (Meter.class.equals(key.getTargetType())) { + @SuppressWarnings("unchecked") + InstanceIdentifier meter = (InstanceIdentifier)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); + } +} diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/MeterStatsTracker.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/MeterStatsTracker.java new file mode 100644 index 0000000000..091cbcc1a0 --- /dev/null +++ b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/MeterStatsTracker.java @@ -0,0 +1,114 @@ +/* + * 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 { + 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 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 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, 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 = (InstanceIdentifier)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); + } +} diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/MultipartMessageManager.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/MultipartMessageManager.java index 6f58708e1b..56b205216f 100644 --- a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/MultipartMessageManager.java +++ b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/MultipartMessageManager.java @@ -7,63 +7,53 @@ */ 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 txIdToRequestTypeMap = new ConcurrentHashMap(); + private final Map 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 txIdTotableIdMap = new ConcurrentHashMap(); - - private final int NUMBER_OF_WAIT_CYCLES =2; + private final Map 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; } @@ -79,16 +69,7 @@ public class MultipartMessageManager { 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; @@ -98,75 +79,60 @@ public class MultipartMessageManager { } 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 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); - } + } } } } diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/NodeConnectorStatsTracker.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/NodeConnectorStatsTracker.java new file mode 100644 index 0000000000..00bd27402f --- /dev/null +++ b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/NodeConnectorStatsTracker.java @@ -0,0 +1,84 @@ +/* + * 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 { + 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 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())); + } + } +} diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/NodeStatisticsAger.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/NodeStatisticsAger.java deleted file mode 100644 index 4ecd620543..0000000000 --- a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/NodeStatisticsAger.java +++ /dev/null @@ -1,346 +0,0 @@ -/* - * 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.Date; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -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.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.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.TableKey; -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.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.NodeGroupStatistics; -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.GroupKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId; -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.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.meter.types.rev130918.meter.config.stats.reply.MeterConfigStats; -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.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder; - -/** - * Main responsibility of this class to clean up all the stale statistics data - * associated to Flow,Meter,Group,Queue. - * @author avishnoi@in.ibm.com - * - */ -public class NodeStatisticsAger { - - private final int NUMBER_OF_WAIT_CYCLES =2; - - private final StatisticsProvider statisticsProvider; - - private final NodeKey targetNodeKey; - - private final Map groupDescStatsUpdate - = new ConcurrentHashMap(); - - private final Map meterConfigStatsUpdate - = new ConcurrentHashMap(); - - private final Map flowStatsUpdate - = new ConcurrentHashMap(); - - private final Map queuesStatsUpdate - = new ConcurrentHashMap(); - - public NodeStatisticsAger(StatisticsProvider statisticsProvider, NodeKey nodeKey){ - this.targetNodeKey = nodeKey; - this.statisticsProvider = statisticsProvider; - } - - public 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; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + getOuterType().hashCode(); - 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 (!getOuterType().equals(other.getOuterType())) - return false; - 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 NodeStatisticsAger getOuterType() { - return NodeStatisticsAger.this; - } - - } - - public 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 + getOuterType().hashCode(); - 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 (!getOuterType().equals(other.getOuterType())) { - return false; - } - 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; - } - private NodeStatisticsAger getOuterType() { - return NodeStatisticsAger.this; - } - } - - public NodeKey getTargetNodeKey() { - return targetNodeKey; - } - - public Map getGroupDescStatsUpdate() { - return groupDescStatsUpdate; - } - - public Map getMeterConfigStatsUpdate() { - return meterConfigStatsUpdate; - } - - public Map getFlowStatsUpdate() { - return flowStatsUpdate; - } - - public Map getQueuesStatsUpdate() { - return queuesStatsUpdate; - } - - public void updateGroupDescStats(List list){ - Date expiryTime = getExpiryTime(); - for(GroupDescStats groupDescStats : list) - this.groupDescStatsUpdate.put(groupDescStats, expiryTime); - } - - public void updateMeterConfigStats(List list){ - Date expiryTime = getExpiryTime(); - for(MeterConfigStats meterConfigStats: list) - this.meterConfigStatsUpdate.put(meterConfigStats, expiryTime); - } - - public void updateFlowStats(FlowEntry flowEntry){ - this.flowStatsUpdate.put(flowEntry, getExpiryTime()); - } - public void updateQueueStats(QueueEntry queueEntry){ - this.queuesStatsUpdate.put(queueEntry, getExpiryTime()); - } - - private Date getExpiryTime(){ - Date expires = new Date(); - expires.setTime(expires.getTime()+StatisticsProvider.STATS_THREAD_EXECUTION_TIME*NUMBER_OF_WAIT_CYCLES); - return expires; - } - - public void cleanStaleStatistics(){ - //Clean stale statistics related to group - for (Iterator it = this.groupDescStatsUpdate.keySet().iterator();it.hasNext();){ - GroupDescStats groupDescStats = it.next(); - Date now = new Date(); - Date expiryTime = this.groupDescStatsUpdate.get(groupDescStats); - if(now.after(expiryTime)){ - cleanGroupStatsFromDataStore(groupDescStats ); - it.remove(); - } - } - - //Clean stale statistics related to meter - for (Iterator it = this.meterConfigStatsUpdate.keySet().iterator();it.hasNext();){ - MeterConfigStats meterConfigStats = it.next(); - Date now = new Date(); - Date expiryTime = this.meterConfigStatsUpdate.get(meterConfigStats); - if(now.after(expiryTime)){ - cleanMeterStatsFromDataStore(meterConfigStats); - it.remove(); - } - } - - //Clean stale statistics related to flow - for (Iterator it = this.flowStatsUpdate.keySet().iterator();it.hasNext();){ - FlowEntry flowEntry = it.next(); - Date now = new Date(); - Date expiryTime = this.flowStatsUpdate.get(flowEntry); - if(now.after(expiryTime)){ - cleanFlowStatsFromDataStore(flowEntry); - it.remove(); - } - } - - //Clean stale statistics related to queue - for (Iterator it = this.queuesStatsUpdate.keySet().iterator();it.hasNext();){ - QueueEntry queueEntry = it.next(); - Date now = new Date(); - Date expiryTime = this.queuesStatsUpdate.get(queueEntry); - if(now.after(expiryTime)){ - cleanQueueStatsFromDataStore(queueEntry); - it.remove(); - } - } - - } - - private void cleanQueueStatsFromDataStore(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(); - cleanStaleStatisticsFromDataStore(queueRef); - } - - private void cleanFlowStatsFromDataStore(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(); - - cleanStaleStatisticsFromDataStore(flowRef); - - } - - private void cleanMeterStatsFromDataStore(MeterConfigStats meterConfigStats) { - InstanceIdentifierBuilder 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(); - - cleanStaleStatisticsFromDataStore(nodeMeterConfigStatsAugmentation); - - InstanceIdentifier nodeMeterStatisticsAugmentation = meterRef.augmentation(NodeMeterStatistics.class).toInstance(); - - cleanStaleStatisticsFromDataStore(nodeMeterStatisticsAugmentation); - - } - - private void cleanGroupStatsFromDataStore(GroupDescStats groupDescStats) { - InstanceIdentifierBuilder 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(); - - cleanStaleStatisticsFromDataStore(nodeGroupDescStatsAugmentation); - - InstanceIdentifier nodeGroupStatisticsAugmentation = groupRef.augmentation(NodeGroupStatistics.class).toInstance(); - - cleanStaleStatisticsFromDataStore(nodeGroupStatisticsAugmentation); - } - - private void cleanStaleStatisticsFromDataStore(InstanceIdentifier ii){ - if(ii != null){ - DataModificationTransaction it = this.statisticsProvider.startChange(); - it.removeOperationalData(ii); - it.commit(); - } - } -} diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/NodeStatisticsHandler.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/NodeStatisticsHandler.java new file mode 100644 index 0000000000..6796b4eb87 --- /dev/null +++ b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/NodeStatisticsHandler.java @@ -0,0 +1,326 @@ +/* + * 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 java.util.List; +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.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.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.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.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.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.OpendaylightGroupStatisticsService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.group.features.GroupFeaturesBuilder; +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.inventory.rev130819.NodeRef; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey; +import org.opendaylight.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.OpendaylightMeterStatisticsService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.nodes.node.MeterFeaturesBuilder; +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.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.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.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.Preconditions; + +/** + * This class handles the lifecycle of per-node statistics. It receives data + * from StatisticsListener, stores it in the data store and keeps track of + * when the data should be removed. + * + * @author avishnoi@in.ibm.com + */ +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 MultipartMessageManager msgManager; + private final InstanceIdentifier targetNodeIdentifier; + 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 final TimerTask task = new TimerTask() { + @Override + 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; + } + + @Override + public InstanceIdentifier getNodeIdentifier() { + return targetNodeIdentifier; + } + + @Override + public NodeRef getNodeRef() { + return targetNodeRef; + } + + @Override + public DataModificationTransaction startDataModification() { + return dps.beginTransaction(); + } + + public synchronized void updateGroupDescStats(TransactionAware transaction, Boolean more, List list) { + if (msgManager.isExpectedTransaction(transaction, more)) { + groupDescStats.updateStats(list); + } + } + + public synchronized void updateGroupStats(TransactionAware transaction, Boolean more, List list) { + if (msgManager.isExpectedTransaction(transaction, more)) { + groupStats.updateStats(list); + } + } + + public synchronized void updateMeterConfigStats(TransactionAware transaction, Boolean more, List list) { + if (msgManager.isExpectedTransaction(transaction, more)) { + meterConfigStats.updateStats(list); + } + } + + public synchronized void updateMeterStats(TransactionAware transaction, Boolean more, List list) { + if (msgManager.isExpectedTransaction(transaction, more)) { + meterStats.updateStats(list); + } + } + + public synchronized void updateQueueStats(TransactionAware transaction, Boolean more, List list) { + if (msgManager.isExpectedTransaction(transaction, more)) { + queueStats.updateStats(list); + } + } + + public synchronized void updateFlowTableStats(TransactionAware transaction, Boolean more, List list) { + if (msgManager.isExpectedTransaction(transaction, more)) { + flowTableStats.updateStats(list); + } + } + + public synchronized void updateNodeConnectorStats(TransactionAware transaction, Boolean more, List list) { + if (msgManager.isExpectedTransaction(transaction, more)) { + nodeConnectorStats.updateStats(list); + } + } + + public synchronized void updateAggregateFlowStats(TransactionAware transaction, Boolean more, AggregateFlowStatistics flowStats) { + final Short tableId = msgManager.isExpectedTableTransaction(transaction, more); + if (tableId != null) { + final DataModificationTransaction trans = dps.beginTransaction(); + InstanceIdentifier
tableRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey) + .augmentation(FlowCapableNode.class).child(Table.class, new TableKey(tableId)).toInstance(); + + AggregateFlowStatisticsDataBuilder aggregateFlowStatisticsDataBuilder = new AggregateFlowStatisticsDataBuilder(); + AggregateFlowStatisticsBuilder aggregateFlowStatisticsBuilder = new AggregateFlowStatisticsBuilder(flowStats); + + aggregateFlowStatisticsDataBuilder.setAggregateFlowStatistics(aggregateFlowStatisticsBuilder.build()); + + logger.debug("Augment aggregate statistics: {} for table {} on Node {}", + aggregateFlowStatisticsBuilder.build().toString(),tableId,targetNodeKey); + + TableBuilder tableBuilder = new TableBuilder(); + tableBuilder.setKey(new TableKey(tableId)); + tableBuilder.addAugmentation(AggregateFlowStatisticsData.class, aggregateFlowStatisticsDataBuilder.build()); + trans.putOperationalData(tableRef, tableBuilder.build()); + + trans.commit(); + } + } + + public synchronized void updateFlowStats(TransactionAware transaction, Boolean more, List list) { + if (msgManager.isExpectedTransaction(transaction, more)) { + flowStats.updateStats(list); + } + } + + public synchronized void updateGroupFeatures(GroupFeatures notification) { + final DataModificationTransaction trans = dps.beginTransaction(); + + final NodeBuilder nodeData = new NodeBuilder(); + nodeData.setKey(targetNodeKey); + + NodeGroupFeaturesBuilder nodeGroupFeatures = new NodeGroupFeaturesBuilder(); + GroupFeaturesBuilder groupFeatures = new GroupFeaturesBuilder(notification); + nodeGroupFeatures.setGroupFeatures(groupFeatures.build()); + + //Update augmented data + nodeData.addAugmentation(NodeGroupFeatures.class, nodeGroupFeatures.build()); + trans.putOperationalData(targetNodeIdentifier, nodeData.build()); + + // FIXME: should we be tracking this data? + trans.commit(); + } + + public synchronized void updateMeterFeatures(MeterFeatures features) { + final DataModificationTransaction trans = dps.beginTransaction(); + + final NodeBuilder nodeData = new NodeBuilder(); + nodeData.setKey(targetNodeKey); + + NodeMeterFeaturesBuilder nodeMeterFeatures = new NodeMeterFeaturesBuilder(); + MeterFeaturesBuilder meterFeature = new MeterFeaturesBuilder(features); + nodeMeterFeatures.setMeterFeatures(meterFeature.build()); + + //Update augmented data + nodeData.addAugmentation(NodeMeterFeatures.class, nodeMeterFeatures.build()); + trans.putOperationalData(targetNodeIdentifier, nodeData.build()); + + // FIXME: should we be tracking this data? + trans.commit(); + } + + public synchronized void cleanStaleStatistics() { + final DataModificationTransaction trans = dps.beginTransaction(); + final long now = System.nanoTime(); + + flowStats.cleanup(trans, now); + groupDescStats.cleanup(trans, now); + groupStats.cleanup(trans, now); + meterConfigStats.cleanup(trans, now); + meterStats.cleanup(trans, now); + nodeConnectorStats.cleanup(trans, now); + queueStats.cleanup(trans, now); + msgManager.cleanStaleTransactionIds(); + + trans.commit(); + } + + public synchronized void requestPeriodicStatistics() { + logger.debug("Send requests for statistics collection to node : {}", targetNodeKey); + + flowTableStats.request(); + + // FIXME: it does not make sense to trigger this before sendAllFlowTablesStatisticsRequest() + // comes back -- we do not have any tables anyway. + final Collection tables = flowTableStats.getTables(); + logger.debug("Node {} supports {} table(s)", targetNodeKey, tables.size()); + for (final TableKey key : tables) { + logger.debug("Send aggregate stats request for flow table {} to node {}", key.getId(), targetNodeKey); + flowStats.requestAggregateFlows(key); + } + + flowStats.requestAllFlowsAllTables(); + nodeConnectorStats.request(); + groupStats.request(); + groupDescStats.request(); + meterStats.request(); + meterConfigStats.request(); + queueStats.request(); + } + + 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); + + timer.schedule(task, (long) (Math.random() * FIRST_COLLECTION_MILLIS), STATS_COLLECTION_MILLIS); + + logger.debug("Statistics handler for node started with base interval {}ms", STATS_COLLECTION_MILLIS); + + requestPeriodicStatistics(); + } + + @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()); + } + + @Override + public void registerTransaction(TransactionId id) { + msgManager.recordExpectedTransaction(id); + logger.debug("Transaction {} for node {} sent successfully", id, targetNodeKey); + } + + @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); + } +} diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/QueueStatsEntry.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/QueueStatsEntry.java new file mode 100644 index 0000000000..d1f2529de8 --- /dev/null +++ b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/QueueStatsEntry.java @@ -0,0 +1,62 @@ +/* + * 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; + } +} diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/QueueStatsTracker.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/QueueStatsTracker.java new file mode 100644 index 0000000000..f187c7082e --- /dev/null +++ b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/QueueStatsTracker.java @@ -0,0 +1,154 @@ +/* + * 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 { + 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 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, DataObject> change) { + for (Entry, 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 = (InstanceIdentifier)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); + } +} diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/RPCFailedException.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/RPCFailedException.java new file mode 100644 index 0000000000..308c6ddebe --- /dev/null +++ b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/RPCFailedException.java @@ -0,0 +1,27 @@ +/* + * 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 errors; + + public RPCFailedException(final String message, final Collection errors) { + super(message); + this.errors = errors; + } + + @Override + public String toString() { + return "RPCFailedException [errors=" + errors + ", message=" + getMessage() + ']'; + } +} diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsListener.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsListener.java new file mode 100644 index 0000000000..bd9f96c875 --- /dev/null +++ b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsListener.java @@ -0,0 +1,144 @@ +/* + * 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.statistics.rev130819.AggregateFlowStatisticsUpdate; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.FlowsStatisticsUpdate; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.OpendaylightFlowStatisticsListener; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.FlowTableStatisticsUpdate; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.OpendaylightFlowTableStatisticsListener; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GroupDescStatsUpdated; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GroupFeaturesUpdated; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GroupStatisticsUpdated; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.OpendaylightGroupStatisticsListener; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.MeterConfigStatsUpdated; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.MeterFeaturesUpdated; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.MeterStatisticsUpdated; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.OpendaylightMeterStatisticsListener; +import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.NodeConnectorStatisticsUpdate; +import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.OpendaylightPortStatisticsListener; +import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.OpendaylightQueueStatisticsListener; +import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.QueueStatisticsUpdate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * This class is responsible for listening for statistics update notifications and + * routing them to the appropriate NodeStatisticsHandler. + + * TODO: Need to add error message listener and clean-up the associated tx id + * if it exists in the tx-id cache. + * @author vishnoianil + */ +public class StatisticsListener implements OpendaylightGroupStatisticsListener, + OpendaylightMeterStatisticsListener, + OpendaylightFlowStatisticsListener, + OpendaylightPortStatisticsListener, + OpendaylightFlowTableStatisticsListener, + OpendaylightQueueStatisticsListener{ + + private final static Logger sucLogger = LoggerFactory.getLogger(StatisticsListener.class); + private final StatisticsProvider statisticsManager; + + /** + * default ctor + * @param manager + */ + public StatisticsListener(final StatisticsProvider manager){ + this.statisticsManager = manager; + } + + @Override + public void onMeterConfigStatsUpdated(final MeterConfigStatsUpdated notification) { + final NodeStatisticsHandler handler = this.statisticsManager.getStatisticsHandler(notification.getId()); + if (handler != null) { + handler.updateMeterConfigStats(notification, notification.isMoreReplies(), notification.getMeterConfigStats()); + } + } + + @Override + public void onMeterStatisticsUpdated(MeterStatisticsUpdated notification) { + final NodeStatisticsHandler handler = this.statisticsManager.getStatisticsHandler(notification.getId()); + if (handler != null) { + handler.updateMeterStats(notification, notification.isMoreReplies(), notification.getMeterStats()); + } + } + + @Override + public void onGroupDescStatsUpdated(GroupDescStatsUpdated notification) { + final NodeStatisticsHandler handler = statisticsManager.getStatisticsHandler(notification.getId()); + if (handler != null) { + handler.updateGroupDescStats(notification, notification.isMoreReplies(), notification.getGroupDescStats()); + } + } + + @Override + public void onGroupStatisticsUpdated(GroupStatisticsUpdated notification) { + final NodeStatisticsHandler handler = statisticsManager.getStatisticsHandler(notification.getId()); + if (handler != null) { + handler.updateGroupStats(notification, notification.isMoreReplies(), notification.getGroupStats()); + } + } + + @Override + public void onMeterFeaturesUpdated(MeterFeaturesUpdated notification) { + final NodeStatisticsHandler sna = this.statisticsManager.getStatisticsHandler(notification.getId()); + if (sna != null) { + sna.updateMeterFeatures(notification); + } + } + + @Override + public void onGroupFeaturesUpdated(GroupFeaturesUpdated notification) { + final NodeStatisticsHandler sna = this.statisticsManager.getStatisticsHandler(notification.getId()); + if (sna != null) { + sna.updateGroupFeatures(notification); + } + } + + @Override + public void onFlowsStatisticsUpdate(final FlowsStatisticsUpdate notification) { + sucLogger.debug("Received flow stats update : {}",notification.toString()); + final NodeStatisticsHandler sna = this.statisticsManager.getStatisticsHandler(notification.getId()); + if (sna != null) { + sna.updateFlowStats(notification, notification.isMoreReplies(), notification.getFlowAndStatisticsMapList()); + } + } + + @Override + public void onAggregateFlowStatisticsUpdate(AggregateFlowStatisticsUpdate notification) { + final NodeStatisticsHandler handler = this.statisticsManager.getStatisticsHandler(notification.getId()); + if (handler != null) { + handler.updateAggregateFlowStats(notification, notification.isMoreReplies(), notification); + } + } + + @Override + public void onNodeConnectorStatisticsUpdate(NodeConnectorStatisticsUpdate notification) { + final NodeStatisticsHandler handler = this.statisticsManager.getStatisticsHandler(notification.getId()); + if (handler != null) { + handler.updateNodeConnectorStats(notification, notification.isMoreReplies(), notification.getNodeConnectorStatisticsAndPortNumberMap()); + } + } + + @Override + public void onFlowTableStatisticsUpdate(FlowTableStatisticsUpdate notification) { + final NodeStatisticsHandler handler = this.statisticsManager.getStatisticsHandler(notification.getId()); + if (handler != null) { + handler.updateFlowTableStats(notification, notification.isMoreReplies(), notification.getFlowTableAndStatisticsMap()); + } + } + + @Override + public void onQueueStatisticsUpdate(QueueStatisticsUpdate notification) { + final NodeStatisticsHandler handler = this.statisticsManager.getStatisticsHandler(notification.getId()); + if (handler != null) { + handler.updateQueueStats(notification, notification.isMoreReplies(), notification.getQueueIdAndStatisticsMap()); + } + } +} diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsManagerActivator.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsManagerActivator.java index 653cc8081a..5bcbef119a 100644 --- a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsManagerActivator.java +++ b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsManagerActivator.java @@ -11,37 +11,26 @@ package org.opendaylight.controller.md.statistics.manager; import org.opendaylight.controller.sal.binding.api.AbstractBindingAwareProvider; import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext; import org.opendaylight.controller.sal.binding.api.NotificationProviderService; -import org.opendaylight.controller.sal.binding.api.data.DataBrokerService; import org.opendaylight.controller.sal.binding.api.data.DataProviderService; import org.osgi.framework.BundleContext; public class StatisticsManagerActivator extends AbstractBindingAwareProvider { + private StatisticsProvider statsProvider; - private static ProviderContext pSession; - - private static StatisticsProvider statsProvider = new StatisticsProvider(); - @Override public void onSessionInitiated(ProviderContext session) { - - pSession = session; - DataProviderService dps = session.getSALService(DataProviderService.class); - StatisticsManagerActivator.statsProvider.setDataService(dps); - DataBrokerService dbs = session.getSALService(DataBrokerService.class); - StatisticsManagerActivator.statsProvider.setDataBrokerService(dbs); - NotificationProviderService nps = session.getSALService(NotificationProviderService.class); - StatisticsManagerActivator.statsProvider.setNotificationService(nps); - StatisticsManagerActivator.statsProvider.start(); + final DataProviderService dps = session.getSALService(DataProviderService.class); + final NotificationProviderService nps = session.getSALService(NotificationProviderService.class); + statsProvider = new StatisticsProvider(dps); + statsProvider.start(nps, session); } - + @Override protected void stopImpl(BundleContext context) { - StatisticsManagerActivator.statsProvider.close(); - } - - public static ProviderContext getProviderContext(){ - return pSession; + if (statsProvider != null) { + statsProvider.close(); + statsProvider = null; + } } - } diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsProvider.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsProvider.java index 325b342cd8..892d304daa 100644 --- a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsProvider.java +++ b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsProvider.java @@ -7,540 +7,163 @@ */ 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.data.DataBrokerService; -import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction; +import org.opendaylight.controller.sal.binding.api.RpcConsumerRegistry; +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; -/** +import com.google.common.base.Preconditions; + +/** * Following are main responsibilities of the class: - * 1) Invoke statistics request thread to send periodic statistics request to all the - * flow capable switch connected to the controller. It sends statistics request for - * Group,Meter,Table,Flow,Queue,Aggregate stats. - * - * 2) Invoke statistics ager thread, to clean up all the stale statistics data from + * 1) Invoke statistics request thread to send periodic statistics request to all the + * flow capable switch connected to the controller. It sends statistics request for + * Group,Meter,Table,Flow,Queue,Aggregate stats. + * + * 2) Invoke statistics ager thread, to clean up all the stale statistics data from * operational data store. - * + * * @author avishnoi@in.ibm.com * */ public class StatisticsProvider implements AutoCloseable { + private static final Logger spLogger = LoggerFactory.getLogger(StatisticsProvider.class); - public final static Logger spLogger = LoggerFactory.getLogger(StatisticsProvider.class); - - private DataProviderService dps; - - private DataBrokerService dbs; + private final ConcurrentMap handlers = new ConcurrentHashMap<>(); + private final Timer timer = new Timer("statistics-manager", true); + private final DataProviderService dps; - private NotificationProviderService nps; - private OpendaylightGroupStatisticsService groupStatsService; - + private OpendaylightMeterStatisticsService meterStatsService; - + private OpendaylightFlowStatisticsService flowStatsService; - + private OpendaylightPortStatisticsService portStatsService; private OpendaylightFlowTableStatisticsService flowTableStatsService; private OpendaylightQueueStatisticsService queueStatsService; - private final MultipartMessageManager multipartMessageManager = new MultipartMessageManager(); - - private StatisticsUpdateHandler statsUpdateHandler; - - private Thread statisticsRequesterThread; - - private Thread statisticsAgerThread; - - private final InstanceIdentifier nodesIdentifier = InstanceIdentifier.builder(Nodes.class).toInstance(); - - public static final int STATS_THREAD_EXECUTION_TIME= 15000; - //Local caching of stats - - private final ConcurrentMap statisticsCache = - new ConcurrentHashMap(); - - public DataProviderService getDataService() { - return this.dps; - } - - public void setDataService(final DataProviderService dataService) { - this.dps = dataService; - } - - public DataBrokerService getDataBrokerService() { - return this.dbs; - } - - public void setDataBrokerService(final DataBrokerService dataBrokerService) { - this.dbs = dataBrokerService; - } - - public NotificationProviderService getNotificationService() { - return this.nps; - } - - public void setNotificationService(final NotificationProviderService notificationService) { - this.nps = notificationService; + public StatisticsProvider(final DataProviderService dataService) { + this.dps = Preconditions.checkNotNull(dataService); } - public MultipartMessageManager getMultipartMessageManager() { - return multipartMessageManager; - } + private final StatisticsListener updateCommiter = new StatisticsListener(StatisticsProvider.this); - private final StatisticsUpdateCommiter updateCommiter = new StatisticsUpdateCommiter(StatisticsProvider.this); - private Registration listenerRegistration; - - public void start() { - - NotificationProviderService nps = this.getNotificationService(); - Registration registerNotificationListener = nps.registerNotificationListener(this.updateCommiter); - this.listenerRegistration = registerNotificationListener; - - statsUpdateHandler = new StatisticsUpdateHandler(StatisticsProvider.this); - - registerDataStoreUpdateListener(this.getDataBrokerService()); - - // Get Group/Meter statistics service instance - groupStatsService = StatisticsManagerActivator.getProviderContext(). - getRpcService(OpendaylightGroupStatisticsService.class); - - meterStatsService = StatisticsManagerActivator.getProviderContext(). - getRpcService(OpendaylightMeterStatisticsService.class); - - flowStatsService = StatisticsManagerActivator.getProviderContext(). - getRpcService(OpendaylightFlowStatisticsService.class); - - portStatsService = StatisticsManagerActivator.getProviderContext(). - getRpcService(OpendaylightPortStatisticsService.class); - flowTableStatsService = StatisticsManagerActivator.getProviderContext(). - getRpcService(OpendaylightFlowTableStatisticsService.class); - - queueStatsService = StatisticsManagerActivator.getProviderContext(). - getRpcService(OpendaylightQueueStatisticsService.class); - - statisticsRequesterThread = new Thread( new Runnable(){ + private ListenerRegistration flowCapableTrackerRegistration; - @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(NodeStatisticsAger 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); + public void start(final NotificationProviderService nps, final RpcConsumerRegistry rpcRegistry) { - statisticsAgerThread.start(); - - spLogger.info("Statistics Provider started."); - } - - private void registerDataStoreUpdateListener(DataBrokerService dbs) { - //Register for Node updates - InstanceIdentifier pathNode = InstanceIdentifier.builder(Nodes.class) - .child(Node.class).toInstance(); - dbs.registerDataChangeListener(pathNode, statsUpdateHandler); + // Get Group/Meter statistics service instances + groupStatsService = rpcRegistry.getRpcService(OpendaylightGroupStatisticsService.class); + meterStatsService = rpcRegistry.getRpcService(OpendaylightMeterStatisticsService.class); + flowStatsService = rpcRegistry.getRpcService(OpendaylightFlowStatisticsService.class); + portStatsService = rpcRegistry.getRpcService(OpendaylightPortStatisticsService.class); + flowTableStatsService = rpcRegistry.getRpcService(OpendaylightFlowTableStatisticsService.class); + queueStatsService = rpcRegistry.getRpcService(OpendaylightQueueStatisticsService.class); - //Register for flow updates - InstanceIdentifier 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 pathMeter = InstanceIdentifier.builder(Nodes.class).child(Node.class) - .augmentation(FlowCapableNode.class) - .child(Meter.class).toInstance(); + // Start receiving notifications + this.listenerRegistration = nps.registerNotificationListener(this.updateCommiter); - dbs.registerDataChangeListener(pathMeter, statsUpdateHandler); - - //Register for group updates - InstanceIdentifier pathGroup = InstanceIdentifier.builder(Nodes.class).child(Node.class) - .augmentation(FlowCapableNode.class) - .child(Group.class).toInstance(); - dbs.registerDataChangeListener(pathGroup, statsUpdateHandler); + // Register for switch connect/disconnect notifications + final InstanceIdentifier 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)); - //Register for queue updates - InstanceIdentifier 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() { - - DataProviderService dps = this.getDataService(); - return dps.beginTransaction(); + spLogger.info("Statistics Provider started."); } - - private void statsRequestSender(){ - - List targetNodes = getAllConnectedNodes(); - - if(targetNodes == null) - return; - - for (Node targetNode : targetNodes){ - - if(targetNode.getAugmentation(FlowCapableNode.class) != null){ - sendStatisticsRequestsToNode(targetNode); - } + /** + * Get the handler for a particular node. + * + * @param nodeId source node + * @return Node statistics handler for that node. Null if the statistics should + * not handled. + */ + public final NodeStatisticsHandler getStatisticsHandler(final NodeId nodeId) { + Preconditions.checkNotNull(nodeId); + NodeStatisticsHandler handler = handlers.get(nodeId); + if (handler == null) { + spLogger.info("Attempted to get non-existing handler for {}", nodeId); } + return handler; } - - public void sendStatisticsRequestsToNode(Node targetNode){ - - spLogger.debug("Send requests for statistics collection to node : {})",targetNode.getId()); - - InstanceIdentifier 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); + + @Override + public void close() { + try { + if (this.listenerRegistration != null) { + this.listenerRegistration.close(); + this.listenerRegistration = null; } - if(queueStatsService != null){ - sendAllQueueStatsFromAllNodeConnector (targetNodeRef); + if (this.flowCapableTrackerRegistration != null) { + this.flowCapableTrackerRegistration.close(); + this.flowCapableTrackerRegistration = null; } - }catch(Exception e){ - spLogger.error("Exception occured while sending statistics requests : {}", e); + timer.cancel(); + } catch (Exception e) { + spLogger.warn("Failed to stop Statistics Provider completely", e); + } finally { + spLogger.info("Statistics Provider stopped."); } } - - - public void sendAllFlowTablesStatisticsRequest(NodeRef targetNodeRef) throws InterruptedException, ExecutionException { - final GetFlowTablesStatisticsInputBuilder input = - new GetFlowTablesStatisticsInputBuilder(); - - input.setNode(targetNodeRef); - - Future> 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> 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> 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 tablesId = getTablesFromNode(targetNodeKey); - - if(tablesId.size() != 0){ - for(Short id : tablesId){ - - sendAggregateFlowsStatsFromTableRequest(targetNodeKey,id); + void startNodeHandlers(final Collection addedNodes) { + for (NodeKey key : addedNodes) { + if (handlers.containsKey(key.getId())) { + spLogger.warn("Attempted to start already-existing handler for {}, very strange", key.getId()); + continue; } - }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> 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> 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> 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> 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> 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> 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> 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> response = - queueStatsService.getQueueStatisticsFromGivenPort(input.build()); - - this.multipartMessageManager.addTxIdToRequestTypeEntry(getNodeId(targetNode), response.get().getResult().getTransactionId() - , StatsRequestType.ALL_QUEUE_STATS);; - - } - - public ConcurrentMap getStatisticsCache() { - return statisticsCache; - } - - private List 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 getTablesFromNode(NodeKey nodeKey){ - InstanceIdentifier nodesIdentifier = InstanceIdentifier.builder(Nodes.class).child(Node.class,nodeKey).augmentation(FlowCapableNode.class).toInstance(); - - FlowCapableNode node = (FlowCapableNode)dps.readOperationalData(nodesIdentifier); - List tablesId = new ArrayList(); - 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()); + 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()); } } - return tablesId; } - @SuppressWarnings("unchecked") - private NodeId getNodeId(NodeRef nodeRef){ - InstanceIdentifier nodeII = (InstanceIdentifier) nodeRef.getValue(); - NodeKey nodeKey = InstanceIdentifier.keyOf(nodeII); - return nodeKey.getId(); - } - - @SuppressWarnings("deprecation") - @Override - public void close(){ - - try { - spLogger.info("Statistics Provider stopped."); - if (this.listenerRegistration != null) { - - this.listenerRegistration.close(); - - this.statisticsRequesterThread.destroy(); - - this.statisticsAgerThread.destroy(); - + void stopNodeHandlers(final Collection 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()); } - } catch (Throwable e) { - throw Exceptions.sneakyThrow(e); - } + } } - } diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsUpdateCommiter.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsUpdateCommiter.java deleted file mode 100644 index 5f264abc2c..0000000000 --- a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsUpdateCommiter.java +++ /dev/null @@ -1,959 +0,0 @@ -/* - * 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.net.Inet4Address; -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.util.List; -import java.util.concurrent.ConcurrentMap; - -import org.opendaylight.controller.md.statistics.manager.NodeStatisticsAger.FlowEntry; -import org.opendaylight.controller.md.statistics.manager.NodeStatisticsAger.QueueEntry; -import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix; -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.AggregateFlowStatisticsUpdate; -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.FlowsStatisticsUpdate; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.OpendaylightFlowStatisticsListener; -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.FlowTableStatisticsUpdate; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.OpendaylightFlowTableStatisticsListener; -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.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.rev131026.flow.Match; -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GroupDescStatsUpdated; -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GroupFeaturesUpdated; -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GroupStatisticsUpdated; -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.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.OpendaylightGroupStatisticsListener; -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.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.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.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.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.MeterConfigStatsUpdated; -import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.MeterFeaturesUpdated; -import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.MeterStatisticsUpdated; -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.OpendaylightMeterStatisticsListener; -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.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.match.types.rev131026.match.Layer3Match; -import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv4Match; -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.NodeConnectorStatisticsUpdate; -import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.OpendaylightPortStatisticsListener; -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.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.OpendaylightQueueStatisticsListener; -import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.QueueStatisticsUpdate; -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.InstanceIdentifier; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Class implement statistics manager related listener interface and augment all the - * received statistics data to data stores. - * TODO: Need to add error message listener and clean-up the associated tx id - * if it exists in the tx-id cache. - * @author vishnoianil - * - */ -public class StatisticsUpdateCommiter implements OpendaylightGroupStatisticsListener, - OpendaylightMeterStatisticsListener, - OpendaylightFlowStatisticsListener, - OpendaylightPortStatisticsListener, - OpendaylightFlowTableStatisticsListener, - OpendaylightQueueStatisticsListener{ - - public final static Logger sucLogger = LoggerFactory.getLogger(StatisticsUpdateCommiter.class); - - private final StatisticsProvider statisticsManager; - private final MultipartMessageManager messageManager; - - private int unaccountedFlowsCounter = 1; - - public StatisticsUpdateCommiter(final StatisticsProvider manager){ - - this.statisticsManager = manager; - this.messageManager = this.statisticsManager.getMultipartMessageManager(); - } - - public StatisticsProvider getStatisticsManager(){ - return statisticsManager; - } - - @Override - public void onMeterConfigStatsUpdated(MeterConfigStatsUpdated notification) { - //Check if response is for the request statistics-manager sent. - if(!messageManager.isRequestTxIdExist(notification.getId(),notification.getTransactionId(),notification.isMoreReplies())) - return; - - NodeKey key = new NodeKey(notification.getId()); - - //Add statistics to local cache - ConcurrentMap cache = this.statisticsManager.getStatisticsCache(); - if(!cache.containsKey(notification.getId())){ - cache.put(notification.getId(), new NodeStatisticsAger(statisticsManager,key)); - } - cache.get(notification.getId()).updateMeterConfigStats(notification.getMeterConfigStats()); - - //Publish data to configuration data store - List meterConfigStatsList = notification.getMeterConfigStats(); - - for(MeterConfigStats meterConfigStats : meterConfigStatsList){ - DataModificationTransaction it = this.statisticsManager.startChange(); - MeterBuilder meterBuilder = new MeterBuilder(); - MeterKey meterKey = new MeterKey(meterConfigStats.getMeterId()); - meterBuilder.setKey(meterKey); - - InstanceIdentifier meterRef = InstanceIdentifier.builder(Nodes.class).child(Node.class,key) - .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()); - it.putOperationalData(meterRef, meterBuilder.build()); - it.commit(); - - } - } - - @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; - - NodeKey key = new NodeKey(notification.getId()); - - List meterStatsList = notification.getMeterStats(); - - for(MeterStats meterStats : meterStatsList){ - - //Publish data to configuration data store - DataModificationTransaction it = this.statisticsManager.startChange(); - MeterBuilder meterBuilder = new MeterBuilder(); - MeterKey meterKey = new MeterKey(meterStats.getMeterId()); - meterBuilder.setKey(meterKey); - - InstanceIdentifier meterRef = InstanceIdentifier.builder(Nodes.class).child(Node.class,key) - .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()); - it.putOperationalData(meterRef, meterBuilder.build()); - it.commit(); - } - } - - @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; - - NodeKey key = new NodeKey(notification.getId()); - - //Add statistics to local cache - ConcurrentMap cache = this.statisticsManager.getStatisticsCache(); - if(!cache.containsKey(notification.getId())){ - cache.put(notification.getId(), new NodeStatisticsAger(statisticsManager,key)); - } - cache.get(notification.getId()).updateGroupDescStats(notification.getGroupDescStats()); - - //Publish data to configuration data store - List groupDescStatsList = notification.getGroupDescStats(); - - for(GroupDescStats groupDescStats : groupDescStatsList){ - DataModificationTransaction it = this.statisticsManager.startChange(); - - GroupBuilder groupBuilder = new GroupBuilder(); - GroupKey groupKey = new GroupKey(groupDescStats.getGroupId()); - groupBuilder.setKey(groupKey); - - InstanceIdentifier groupRef = InstanceIdentifier.builder(Nodes.class).child(Node.class,key) - .augmentation(FlowCapableNode.class) - .child(Group.class,groupKey).toInstance(); - - NodeGroupDescStatsBuilder groupDesc= new NodeGroupDescStatsBuilder(); - GroupDescBuilder stats = new GroupDescBuilder(); - stats.fieldsFrom(groupDescStats); - groupDesc.setGroupDesc(stats.build()); - - //Update augmented data - groupBuilder.addAugmentation(NodeGroupDescStats.class, groupDesc.build()); - - it.putOperationalData(groupRef, groupBuilder.build()); - it.commit(); - } - } - - @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; - - //Publish data to configuration data store - NodeKey key = new NodeKey(notification.getId()); - List groupStatsList = notification.getGroupStats(); - - for(GroupStats groupStats : groupStatsList){ - DataModificationTransaction it = this.statisticsManager.startChange(); - - GroupBuilder groupBuilder = new GroupBuilder(); - GroupKey groupKey = new GroupKey(groupStats.getGroupId()); - groupBuilder.setKey(groupKey); - - InstanceIdentifier groupRef = InstanceIdentifier.builder(Nodes.class).child(Node.class,key) - .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()); - it.putOperationalData(groupRef, groupBuilder.build()); - it.commit(); - } - } - - @Override - public void onMeterFeaturesUpdated(MeterFeaturesUpdated notification) { - - MeterFeaturesBuilder meterFeature = new MeterFeaturesBuilder(); - meterFeature.setMeterBandSupported(notification.getMeterBandSupported()); - meterFeature.setMeterCapabilitiesSupported(notification.getMeterCapabilitiesSupported()); - meterFeature.setMaxBands(notification.getMaxBands()); - meterFeature.setMaxColor(notification.getMaxColor()); - meterFeature.setMaxMeter(notification.getMaxMeter()); - - //Publish data to configuration data store - DataModificationTransaction it = this.statisticsManager.startChange(); - NodeKey key = new NodeKey(notification.getId()); - NodeRef ref = getNodeRef(key); - - final NodeBuilder nodeData = new NodeBuilder(); - nodeData.setKey(key); - - NodeMeterFeaturesBuilder nodeMeterFeatures= new NodeMeterFeaturesBuilder(); - nodeMeterFeatures.setMeterFeatures(meterFeature.build()); - - //Update augmented data - nodeData.addAugmentation(NodeMeterFeatures.class, nodeMeterFeatures.build()); - - InstanceIdentifier refValue = ref.getValue(); - it.putOperationalData(refValue, nodeData.build()); - it.commit(); - } - - @Override - public void onGroupFeaturesUpdated(GroupFeaturesUpdated notification) { - - GroupFeaturesBuilder groupFeatures = new GroupFeaturesBuilder(); - groupFeatures.setActions(notification.getActions()); - groupFeatures.setGroupCapabilitiesSupported(notification.getGroupCapabilitiesSupported()); - groupFeatures.setGroupTypesSupported(notification.getGroupTypesSupported()); - groupFeatures.setMaxGroups(notification.getMaxGroups()); - - //Publish data to configuration data store - DataModificationTransaction it = this.statisticsManager.startChange(); - NodeKey key = new NodeKey(notification.getId()); - NodeRef ref = getNodeRef(key); - - final NodeBuilder nodeData = new NodeBuilder(); - nodeData.setKey(key); - - NodeGroupFeaturesBuilder nodeGroupFeatures= new NodeGroupFeaturesBuilder(); - nodeGroupFeatures.setGroupFeatures(groupFeatures.build()); - - //Update augmented data - nodeData.addAugmentation(NodeGroupFeatures.class, nodeGroupFeatures.build()); - - InstanceIdentifier refValue = ref.getValue(); - it.putOperationalData(refValue, nodeData.build()); - it.commit(); - } - - @Override - public void onFlowsStatisticsUpdate(FlowsStatisticsUpdate notification) { - - //Check if response is for the request statistics-manager sent. - if(!messageManager.isRequestTxIdExist(notification.getId(),notification.getTransactionId(),notification.isMoreReplies())) - return; - - NodeKey key = new NodeKey(notification.getId()); - sucLogger.debug("Received flow stats update : {}",notification.toString()); - - for(FlowAndStatisticsMapList map: notification.getFlowAndStatisticsMapList()){ - short tableId = map.getTableId(); - - DataModificationTransaction it = this.statisticsManager.startChange(); - - 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(); - - //Add statistics to local cache - ConcurrentMap cache = this.statisticsManager.getStatisticsCache(); - if(!cache.containsKey(notification.getId())){ - cache.put(notification.getId(), new NodeStatisticsAger(statisticsManager,key)); - } - NodeStatisticsAger nsa = cache.get(notification.getId()); - - //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()); - - sucLogger.debug("Flow : {}",flowRule.toString()); - sucLogger.debug("Statistics to augment : {}",flowStatistics.build().toString()); - - InstanceIdentifier
tableRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, key) - .augmentation(FlowCapableNode.class).child(Table.class, new TableKey(tableId)).toInstance(); - - Table table= (Table)it.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()){ - sucLogger.debug("Existing flow in data store : {}",existingFlow.toString()); - if(flowEquals(flowRule,existingFlow)){ - it = this.statisticsManager.startChange(); - InstanceIdentifier flowRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, key) - .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()); - sucLogger.debug("Found matching flow in the datastore, augmenting statistics"); - foundOriginalFlow = true; - // Update entry with timestamp of latest response - flow.setKey(existingFlow.getKey()); - FlowEntry flowStatsEntry = nsa.new FlowEntry(tableId,flow.build()); - cache.get(notification.getId()).updateFlowStats(flowStatsEntry); - - it.putOperationalData(flowRef, flowBuilder.build()); - it.commit(); - } - } - } - - table= (Table)it.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()); - sucLogger.debug("Existing unaccounted flow in operational data store : {}",existingFlow.toString()); - if(flowEquals(flowRule,existingOperationalFlow.build())){ - InstanceIdentifier flowRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, key) - .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()); - sucLogger.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 = nsa.new FlowEntry(tableId,flow.build()); - cache.get(notification.getId()).updateFlowStats(flowStatsEntry); - - it.putOperationalData(flowRef, flowBuilder.build()); - it.commit(); - break; - } - } - } - } - if(!foundOriginalFlow){ - String flowKey = "#UF$TABLE*"+Short.toString(tableId)+"*"+Integer.toString(this.unaccountedFlowsCounter); - this.unaccountedFlowsCounter++; - FlowKey newFlowKey = new FlowKey(new FlowId(flowKey)); - InstanceIdentifier flowRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, key) - .augmentation(FlowCapableNode.class) - .child(Table.class, new TableKey(tableId)) - .child(Flow.class,newFlowKey).toInstance(); - flowBuilder.setKey(newFlowKey); - flowBuilder.addAugmentation(FlowStatisticsData.class, flowStatisticsData.build()); - sucLogger.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 = nsa.new FlowEntry(tableId,flow.build()); - cache.get(notification.getId()).updateFlowStats(flowStatsEntry); - - it.putOperationalData(flowRef, flowBuilder.build()); - it.commit(); - } - } - } - - @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; - - NodeKey key = new NodeKey(notification.getId()); - - Short tableId = messageManager.getTableIdForTxId(notification.getId(),notification.getTransactionId()); - if(tableId != null){ - - DataModificationTransaction it = this.statisticsManager.startChange(); - - InstanceIdentifier
tableRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, key) - .augmentation(FlowCapableNode.class).child(Table.class, new TableKey(tableId)).toInstance(); - - AggregateFlowStatisticsDataBuilder aggregateFlowStatisticsDataBuilder = new AggregateFlowStatisticsDataBuilder(); - AggregateFlowStatisticsBuilder aggregateFlowStatisticsBuilder = new AggregateFlowStatisticsBuilder(); - aggregateFlowStatisticsBuilder.setByteCount(notification.getByteCount()); - aggregateFlowStatisticsBuilder.setFlowCount(notification.getFlowCount()); - aggregateFlowStatisticsBuilder.setPacketCount(notification.getPacketCount()); - aggregateFlowStatisticsDataBuilder.setAggregateFlowStatistics(aggregateFlowStatisticsBuilder.build()); - - sucLogger.debug("Augment aggregate statistics: {} for table {} on Node {}",aggregateFlowStatisticsBuilder.build().toString(),tableId,key); - - TableBuilder tableBuilder = new TableBuilder(); - tableBuilder.setKey(new TableKey(tableId)); - tableBuilder.addAugmentation(AggregateFlowStatisticsData.class, aggregateFlowStatisticsDataBuilder.build()); - it.putOperationalData(tableRef, tableBuilder.build()); - it.commit(); - - } - } - - @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; - - NodeKey key = new NodeKey(notification.getId()); - - List portsStats = notification.getNodeConnectorStatisticsAndPortNumberMap(); - for(NodeConnectorStatisticsAndPortNumberMap portStats : portsStats){ - - DataModificationTransaction it = this.statisticsManager.startChange(); - - 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 nodeConnectorRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, key).child(NodeConnector.class, new NodeConnectorKey(portStats.getNodeConnectorId())).toInstance(); - - NodeConnector nodeConnector = (NodeConnector)it.readOperationalData(nodeConnectorRef); - - if(nodeConnector != null){ - sucLogger.debug("Augmenting port statistics {} to port {}",statisticsDataBuilder.build().toString(),nodeConnectorRef.toString()); - NodeConnectorBuilder nodeConnectorBuilder = new NodeConnectorBuilder(); - nodeConnectorBuilder.addAugmentation(FlowCapableNodeConnectorStatisticsData.class, statisticsDataBuilder.build()); - it.putOperationalData(nodeConnectorRef, nodeConnectorBuilder.build()); - it.commit(); - } - } - } - - @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; - - NodeKey key = new NodeKey(notification.getId()); - - List flowTablesStatsList = notification.getFlowTableAndStatisticsMap(); - for (FlowTableAndStatisticsMap ftStats : flowTablesStatsList){ - - DataModificationTransaction it = this.statisticsManager.startChange(); - - InstanceIdentifier
tableRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, key) - .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()); - - statisticsDataBuilder.setFlowTableStatistics(statisticsBuilder.build()); - - sucLogger.debug("Augment flow table statistics: {} for table {} on Node {}",statisticsBuilder.build().toString(),ftStats.getTableId(),key); - - TableBuilder tableBuilder = new TableBuilder(); - tableBuilder.setKey(new TableKey(ftStats.getTableId().getValue())); - tableBuilder.addAugmentation(FlowTableStatisticsData.class, statisticsDataBuilder.build()); - it.putOperationalData(tableRef, tableBuilder.build()); - it.commit(); - } - } - - @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; - - NodeKey key = new NodeKey(notification.getId()); - - //Add statistics to local cache - ConcurrentMap cache = this.statisticsManager.getStatisticsCache(); - if(!cache.containsKey(notification.getId())){ - cache.put(notification.getId(), new NodeStatisticsAger(statisticsManager,key)); - } - - NodeStatisticsAger nsa = cache.get(notification.getId()); - - List queuesStats = notification.getQueueIdAndStatisticsMap(); - for(QueueIdAndStatisticsMap swQueueStats : queuesStats){ - - QueueEntry queueEntry = nsa.new QueueEntry(swQueueStats.getNodeConnectorId(),swQueueStats.getQueueId()); - nsa.updateQueueStats(queueEntry); - - FlowCapableNodeConnectorQueueStatisticsDataBuilder queueStatisticsDataBuilder = new FlowCapableNodeConnectorQueueStatisticsDataBuilder(); - - FlowCapableNodeConnectorQueueStatisticsBuilder queueStatisticsBuilder = new FlowCapableNodeConnectorQueueStatisticsBuilder(); - - queueStatisticsBuilder.fieldsFrom(swQueueStats); - - queueStatisticsDataBuilder.setFlowCapableNodeConnectorQueueStatistics(queueStatisticsBuilder.build()); - - DataModificationTransaction it = this.statisticsManager.startChange(); - - InstanceIdentifier queueRef - = InstanceIdentifier.builder(Nodes.class) - .child(Node.class, key) - .child(NodeConnector.class, new NodeConnectorKey(swQueueStats.getNodeConnectorId())) - .augmentation(FlowCapableNodeConnector.class) - .child(Queue.class, new QueueKey(swQueueStats.getQueueId())).toInstance(); - - QueueBuilder queueBuilder = new QueueBuilder(); - queueBuilder.addAugmentation(FlowCapableNodeConnectorQueueStatisticsData.class, queueStatisticsDataBuilder.build()); - queueBuilder.setKey(new QueueKey(swQueueStats.getQueueId())); - - sucLogger.debug("Augmenting queue statistics {} of queue {} to port {}" - ,queueStatisticsDataBuilder.build().toString(), - swQueueStats.getQueueId(), - swQueueStats.getNodeConnectorId()); - - it.putOperationalData(queueRef, queueBuilder.build()); - it.commit(); - - } - - } - - private NodeRef getNodeRef(NodeKey nodeKey){ - InstanceIdentifierBuilder builder = InstanceIdentifier.builder(Nodes.class).child(Node.class, nodeKey); - return new NodeRef(builder.toInstance()); - } - - public boolean flowEquals(Flow statsFlow, Flow storedFlow) { - if (statsFlow.getClass() != storedFlow.getClass()) { - return false; - } - if (statsFlow.getContainerName()== null) { - if (storedFlow.getContainerName()!= null) { - return false; - } - } else if(!statsFlow.getContainerName().equals(storedFlow.getContainerName())) { - return false; - } - if (statsFlow.getMatch()== null) { - if (storedFlow.getMatch() != null) { - return false; - } - } //else if(!statsFlow.getMatch().equals(storedFlow.getMatch())) { - else if(!matchEquals(statsFlow.getMatch(), storedFlow.getMatch())) { - return false; - } - if (storedFlow.getPriority() == null) { - if (statsFlow.getPriority() != null && statsFlow.getPriority()!= 0x8000) { - return false; - } - } else if(!statsFlow.getPriority().equals(storedFlow.getPriority())) { - return false; - } - if (statsFlow.getTableId() == null) { - if (storedFlow.getTableId() != null) { - return false; - } - } else if(!statsFlow.getTableId().equals(storedFlow.getTableId())) { - return false; - } - return true; - } - - /** - * Explicit equals method to compare the 'match' for flows stored in the data-stores and flow fetched from the switch. - * Flow installation process has three steps - * 1) Store flow in config data store - * 2) and send it to plugin for installation - * 3) Flow gets installed in switch - * - * The flow user wants to install and what finally gets installed in switch can be slightly different. - * E.g, If user installs flow with src/dst ip=10.0.0.1/24, when it get installed in the switch - * src/dst ip will be changes to 10.0.0.0/24 because of netmask of 24. When statistics manager fetch - * stats it gets 10.0.0.0/24 rather then 10.0.0.1/24. Custom match takes care of by using masked ip - * while comparing two ip addresses. - * - * Sometimes when user don't provide few values that is required by flow installation request, like - * priority,hard timeout, idle timeout, cookies etc, plugin usages default values before sending - * request to the switch. So when statistics manager gets flow statistics, it gets the default value. - * But the flow stored in config data store don't have those defaults value. I included those checks - * in the customer flow/match equal function. - * - * - * @param statsFlow - * @param storedFlow - * @return - */ - - public boolean matchEquals(Match statsFlow, Match storedFlow) { - if (statsFlow == storedFlow) { - return true; - } - if (storedFlow.getClass() != statsFlow.getClass()) { - return false; - } - if (storedFlow.getEthernetMatch() == null) { - if (statsFlow.getEthernetMatch() != null) { - return false; - } - } else if(!storedFlow.getEthernetMatch().equals(statsFlow.getEthernetMatch())) { - return false; - } - if (storedFlow.getIcmpv4Match()== null) { - if (statsFlow.getIcmpv4Match() != null) { - return false; - } - } else if(!storedFlow.getIcmpv4Match().equals(statsFlow.getIcmpv4Match())) { - return false; - } - if (storedFlow.getIcmpv6Match() == null) { - if (statsFlow.getIcmpv6Match() != null) { - return false; - } - } else if(!storedFlow.getIcmpv6Match().equals(statsFlow.getIcmpv6Match())) { - return false; - } - if (storedFlow.getInPhyPort() == null) { - if (statsFlow.getInPhyPort() != null) { - return false; - } - } else if(!storedFlow.getInPhyPort().equals(statsFlow.getInPhyPort())) { - return false; - } - if (storedFlow.getInPort()== null) { - if (statsFlow.getInPort() != null) { - return false; - } - } else if(!storedFlow.getInPort().equals(statsFlow.getInPort())) { - return false; - } - if (storedFlow.getIpMatch()== null) { - if (statsFlow.getIpMatch() != null) { - return false; - } - } else if(!storedFlow.getIpMatch().equals(statsFlow.getIpMatch())) { - return false; - } - if (storedFlow.getLayer3Match()== null) { - if (statsFlow.getLayer3Match() != null) { - return false; - } - } else if(!layer3MatchEquals(statsFlow.getLayer3Match(),storedFlow.getLayer3Match())) { - return false; - } - if (storedFlow.getLayer4Match()== null) { - if (statsFlow.getLayer4Match() != null) { - return false; - } - } else if(!storedFlow.getLayer4Match().equals(statsFlow.getLayer4Match())) { - return false; - } - if (storedFlow.getMetadata() == null) { - if (statsFlow.getMetadata() != null) { - return false; - } - } else if(!storedFlow.getMetadata().equals(statsFlow.getMetadata())) { - return false; - } - if (storedFlow.getProtocolMatchFields() == null) { - if (statsFlow.getProtocolMatchFields() != null) { - return false; - } - } else if(!storedFlow.getProtocolMatchFields().equals(statsFlow.getProtocolMatchFields())) { - return false; - } - if (storedFlow.getTunnel()== null) { - if (statsFlow.getTunnel() != null) { - return false; - } - } else if(!storedFlow.getTunnel().equals(statsFlow.getTunnel())) { - return false; - } - if (storedFlow.getVlanMatch()== null) { - if (statsFlow.getVlanMatch() != null) { - return false; - } - } else if(!storedFlow.getVlanMatch().equals(statsFlow.getVlanMatch())) { - return false; - } - return true; - } - - private boolean layer3MatchEquals(Layer3Match statsLayer3Match, Layer3Match storedLayer3Match){ - - if(statsLayer3Match instanceof Ipv4Match && storedLayer3Match instanceof Ipv4Match){ - Ipv4Match statsIpv4Match = (Ipv4Match)statsLayer3Match; - Ipv4Match storedIpv4Match = (Ipv4Match)storedLayer3Match; - - if (storedIpv4Match.getIpv4Destination()== null) { - if (statsIpv4Match.getIpv4Destination()!= null) { - return false; - } - } else if(!IpAddressEquals(statsIpv4Match.getIpv4Destination(),storedIpv4Match.getIpv4Destination())){ - return false; - } - if (storedIpv4Match.getIpv4Source() == null) { - if (statsIpv4Match.getIpv4Source() != null) { - return false; - } - } else if(!IpAddressEquals(statsIpv4Match.getIpv4Source(),storedIpv4Match.getIpv4Source())) { - return false; - } - - return true; - }else{ - return storedLayer3Match.equals(statsLayer3Match); - } - } - - private boolean IpAddressEquals(Ipv4Prefix statsIpAddress, Ipv4Prefix storedIpAddress) { - IntegerIpAddress statsIpAddressInt = StrIpToIntIp(statsIpAddress.getValue()); - IntegerIpAddress storedIpAddressInt = StrIpToIntIp(storedIpAddress.getValue()); - - if(IpAndMaskBasedMatch(statsIpAddressInt,storedIpAddressInt)){ - return true; - } - if(IpBasedMatch(statsIpAddressInt,storedIpAddressInt)){ - return true; - } - return false; - } - - private boolean IpAndMaskBasedMatch(IntegerIpAddress statsIpAddressInt,IntegerIpAddress storedIpAddressInt){ - return ((statsIpAddressInt.getIp() & statsIpAddressInt.getMask()) == (storedIpAddressInt.getIp() & storedIpAddressInt.getMask())); - } - - private boolean IpBasedMatch(IntegerIpAddress statsIpAddressInt,IntegerIpAddress storedIpAddressInt){ - return (statsIpAddressInt.getIp() == storedIpAddressInt.getIp()); - } - - /* - * Method return integer version of ip address. Converted int will be mask if - * mask specified - */ - private IntegerIpAddress StrIpToIntIp(String ipAddresss){ - - String[] parts = ipAddresss.split("/"); - String ip = parts[0]; - int prefix; - - if (parts.length < 2) { - prefix = 32; - } else { - prefix = Integer.parseInt(parts[1]); - } - - Inet4Address addr =null; - try { - addr = (Inet4Address) InetAddress.getByName(ip); - } catch (UnknownHostException e){} - - byte[] addrBytes = addr.getAddress(); - int ipInt = ((addrBytes[0] & 0xFF) << 24) | - ((addrBytes[1] & 0xFF) << 16) | - ((addrBytes[2] & 0xFF) << 8) | - ((addrBytes[3] & 0xFF) << 0); - - int mask = 0xffffffff << 32 - prefix; - - return new IntegerIpAddress(ipInt, mask); - } - - class IntegerIpAddress{ - int ip; - int mask; - public IntegerIpAddress(int ip, int mask) { - this.ip = ip; - this.mask = mask; - } - public int getIp() { - return ip; - } - public int getMask() { - return mask; - } - } -} - diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsUpdateHandler.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsUpdateHandler.java deleted file mode 100644 index 941a8f8c2c..0000000000 --- a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsUpdateHandler.java +++ /dev/null @@ -1,169 +0,0 @@ -/* - * 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 { - - public final static Logger suhLogger = LoggerFactory.getLogger(StatisticsUpdateHandler.class); - - private final StatisticsProvider statisticsManager; - - public StatisticsUpdateHandler(final StatisticsProvider manager){ - - this.statisticsManager = manager; - } - - public StatisticsProvider getStatisticsManager(){ - return statisticsManager; - } - - @SuppressWarnings("unchecked") - @Override - public void onDataChanged(DataChangeEvent, DataObject> change) { - - Map, DataObject> nodeAdditions = change.getCreatedOperationalData(); - for (InstanceIdentifier 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, DataObject> additions = change.getCreatedConfigurationData(); - for (InstanceIdentifier dataObjectInstance : additions.keySet()) { - DataObject dataObject = additions.get(dataObjectInstance); - InstanceIdentifier 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 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); - } - } - } - - Set> removals = change.getRemovedConfigurationData(); - for (InstanceIdentifier dataObjectInstance : removals) { - DataObject dataObject = change.getOriginalConfigurationData().get(dataObjectInstance); - - if(dataObject instanceof Flow){ - InstanceIdentifier flowII = (InstanceIdentifier)dataObjectInstance; - InstanceIdentifier flowAugmentation = - InstanceIdentifier.builder(flowII).augmentation(FlowStatisticsData.class).toInstance(); - removeAugmentedOperationalData(flowAugmentation); - } - if(dataObject instanceof Meter){ - InstanceIdentifier meterII = (InstanceIdentifier)dataObjectInstance; - - InstanceIdentifier nodeMeterConfigStatsAugmentation = - InstanceIdentifier.builder(meterII).augmentation(NodeMeterConfigStats.class).toInstance(); - removeAugmentedOperationalData(nodeMeterConfigStatsAugmentation); - - InstanceIdentifier nodeMeterStatisticsAugmentation = - InstanceIdentifier.builder(meterII).augmentation(NodeMeterStatistics.class).toInstance(); - removeAugmentedOperationalData(nodeMeterStatisticsAugmentation); - } - - if(dataObject instanceof Group){ - InstanceIdentifier groupII = (InstanceIdentifier)dataObjectInstance; - - InstanceIdentifier nodeGroupDescStatsAugmentation = - InstanceIdentifier.builder(groupII).augmentation(NodeGroupDescStats.class).toInstance(); - removeAugmentedOperationalData(nodeGroupDescStatsAugmentation); - - InstanceIdentifier nodeGroupStatisticsAugmentation = - InstanceIdentifier.builder(groupII).augmentation(NodeGroupStatistics.class).toInstance(); - removeAugmentedOperationalData(nodeGroupStatisticsAugmentation); - } - - if(dataObject instanceof Queue){ - InstanceIdentifier queueII = (InstanceIdentifier)dataObjectInstance; - - InstanceIdentifier nodeConnectorQueueStatisticsDataAugmentation = - InstanceIdentifier.builder(queueII).augmentation(FlowCapableNodeConnectorQueueStatisticsData.class).toInstance(); - removeAugmentedOperationalData(nodeConnectorQueueStatisticsDataAugmentation); - } - } - } - - private void removeAugmentedOperationalData(InstanceIdentifier dataObjectInstance ){ - if(dataObjectInstance != null){ - DataModificationTransaction it = this.statisticsManager.startChange(); - it.removeOperationalData(dataObjectInstance); - it.commit(); - } - } -} diff --git a/opendaylight/md-sal/statistics-manager/src/test/java/org/opendaylight/controller/md/statistics/manager/StatisticsUpdateCommiterTest.java b/opendaylight/md-sal/statistics-manager/src/test/java/org/opendaylight/controller/md/statistics/manager/StatisticsUpdateCommiterTest.java new file mode 100644 index 0000000000..bf523a433b --- /dev/null +++ b/opendaylight/md-sal/statistics-manager/src/test/java/org/opendaylight/controller/md/statistics/manager/StatisticsUpdateCommiterTest.java @@ -0,0 +1,115 @@ +/** + * 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.junit.Assert; +import org.junit.Test; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix; +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv4Match; +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv4MatchBuilder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + */ +public class StatisticsUpdateCommiterTest { + + private static final Logger LOG = LoggerFactory + .getLogger(StatisticsUpdateCommiterTest.class); + + /** + * Test method for {@link org.opendaylight.controller.md.statistics.manager.StatisticsListener#layer3MatchEquals(org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Layer3Match, org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Layer3Match)}. + */ + @Test + public void testLayer3MatchEquals() { + String[][][] matchSeeds = new String[][][] { + {{"10.1.2.0/24", "10.1.2.0/24"}, {"10.1.2.0/24", "10.1.2.0/24"}}, + {{"10.1.2.0/24", "10.1.2.0/24"}, {"10.1.2.0/24", "10.1.1.0/24"}}, + {{"10.1.1.0/24", "10.1.2.0/24"}, {"10.1.2.0/24", "10.1.2.0/24"}}, + {{"10.1.1.0/24", "10.1.1.0/24"}, {"10.1.2.0/24", "10.1.2.0/24"}}, + + {{"10.1.1.0/24", null}, {"10.1.1.0/24", "10.1.2.0/24"}}, + {{"10.1.1.0/24", null}, {"10.1.2.0/24", "10.1.2.0/24"}}, + {{"10.1.1.0/24", null}, {"10.1.2.0/24", null}}, + {{"10.1.1.0/24", null}, {"10.1.1.0/24", null}}, + + {{null, "10.1.1.0/24"}, {"10.1.2.0/24", "10.1.1.0/24"}}, + {{null, "10.1.1.0/24"}, {"10.1.2.0/24", "10.1.2.0/24"}}, + {{null, "10.1.1.0/24"}, {null, "10.1.2.0/24"}}, + {{null, "10.1.1.0/24"}, {null, "10.1.1.0/24"}}, + + {{null, null}, {null, "10.1.1.0/24"}}, + {{null, null}, {null, null}}, + }; + + boolean[] matches = new boolean[] { + true, + false, + false, + false, + + false, + false, + false, + true, + + false, + false, + false, + true, + + false, + true + }; + + for (int i = 0; i < matches.length; i++) { + checkComparisonOfL3Match( + matchSeeds[i][0][0], matchSeeds[i][0][1], + matchSeeds[i][1][0], matchSeeds[i][1][1], + matches[i]); + } + } + + /** + * @param m1Source match1 - src + * @param m1Destination match1 - dest + * @param m2Source match2 - src + * @param msDestination match2 - dest + * @param matches expected match output + * + */ + private static void checkComparisonOfL3Match(String m1Source, String m1Destination, + String m2Source, String msDestination, boolean matches) { + Ipv4Match m1Layer3 = prepareIPv4Match(m1Source, m1Destination); + Ipv4Match m2Layer3 = prepareIPv4Match(m2Source, msDestination); + boolean comparisonResult; + try { + comparisonResult = FlowComparator.layer3MatchEquals(m1Layer3, m2Layer3); + Assert.assertEquals("failed to compare: "+m1Layer3+" vs. "+m2Layer3, + matches, comparisonResult); + } catch (Exception e) { + LOG.error("failed to compare: {} vs. {}", m1Layer3, m2Layer3, e); + Assert.fail(e.getMessage()); + } + } + + private static Ipv4Match prepareIPv4Match(String source, String destination) { + Ipv4MatchBuilder ipv4MatchBuilder = new Ipv4MatchBuilder(); + if (source != null) { + ipv4MatchBuilder.setIpv4Source(new Ipv4Prefix(source)); + } + if (destination != null) { + ipv4MatchBuilder.setIpv4Destination(new Ipv4Prefix(destination)); + } + + return ipv4MatchBuilder.build(); + } + +} diff --git a/opendaylight/md-sal/statistics-manager/src/test/resources/log4j-test.xml b/opendaylight/md-sal/statistics-manager/src/test/resources/log4j-test.xml new file mode 100644 index 0000000000..bd3bf3cd2c --- /dev/null +++ b/opendaylight/md-sal/statistics-manager/src/test/resources/log4j-test.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/AttributeIfcSwitchStatement.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/AttributeIfcSwitchStatement.java index 502d581220..54d24a4cec 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/AttributeIfcSwitchStatement.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/AttributeIfcSwitchStatement.java @@ -8,6 +8,11 @@ package org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes; +import javax.management.openmbean.ArrayType; +import javax.management.openmbean.CompositeType; +import javax.management.openmbean.OpenType; +import javax.management.openmbean.SimpleType; + import org.opendaylight.controller.config.yangjmxgenerator.attribute.AttributeIfc; import org.opendaylight.controller.config.yangjmxgenerator.attribute.DependencyAttribute; import org.opendaylight.controller.config.yangjmxgenerator.attribute.JavaAttribute; @@ -16,11 +21,6 @@ import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListDepende import org.opendaylight.controller.config.yangjmxgenerator.attribute.TOAttribute; import org.opendaylight.yangtools.yang.model.api.type.BinaryTypeDefinition; -import javax.management.openmbean.ArrayType; -import javax.management.openmbean.CompositeType; -import javax.management.openmbean.OpenType; -import javax.management.openmbean.SimpleType; - public abstract class AttributeIfcSwitchStatement { protected AttributeIfc lastAttribute; @@ -102,6 +102,8 @@ public abstract class AttributeIfcSwitchStatement { protected abstract T caseListDependeciesAttribute(ArrayType openType); private static class UnknownOpenTypeException extends RuntimeException { + private static final long serialVersionUID = 1L; + public UnknownOpenTypeException(String message) { super(message); } diff --git a/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/ConfigPusher.java b/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/ConfigPusher.java index 01d872d89c..460aec6ac6 100644 --- a/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/ConfigPusher.java +++ b/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/ConfigPusher.java @@ -8,16 +8,27 @@ package org.opendaylight.controller.netconf.persist.impl; -import com.google.common.base.Optional; -import com.google.common.base.Preconditions; -import io.netty.channel.EventLoopGroup; +import java.io.IOException; +import java.io.InputStream; +import java.net.InetSocketAddress; +import java.util.Collections; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Set; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +import javax.annotation.concurrent.Immutable; + import org.opendaylight.controller.config.api.ConflictingVersionException; import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder; import org.opendaylight.controller.netconf.api.NetconfMessage; import org.opendaylight.controller.netconf.client.NetconfClient; import org.opendaylight.controller.netconf.client.NetconfClientDispatcher; import org.opendaylight.controller.netconf.util.NetconfUtil; -import org.opendaylight.controller.netconf.util.messages.NetconfMessageAdditionalHeader; +import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessageAdditionalHeader; import org.opendaylight.controller.netconf.util.xml.XmlElement; import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants; import org.opendaylight.controller.netconf.util.xml.XmlUtil; @@ -27,20 +38,12 @@ import org.w3c.dom.Document; import org.w3c.dom.Element; import org.xml.sax.SAXException; -import javax.annotation.concurrent.Immutable; -import java.io.IOException; -import java.io.InputStream; -import java.net.InetSocketAddress; -import java.util.Collections; -import java.util.HashSet; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Set; -import java.util.concurrent.TimeUnit; +import com.google.common.base.Preconditions; +import io.netty.channel.EventLoopGroup; @Immutable public class ConfigPusher { - private static final Logger logger = LoggerFactory.getLogger(ConfigPersisterNotificationHandler.class); + private static final Logger logger = LoggerFactory.getLogger(ConfigPusher.class); private static final int NETCONF_SEND_ATTEMPT_MS_DELAY = 1000; private static final int NETCONF_SEND_ATTEMPTS = 20; @@ -59,7 +62,7 @@ public class ConfigPusher { } public ConfigPusher(InetSocketAddress address, EventLoopGroup nettyThreadGroup, - long maxWaitForCapabilitiesMillis, long connectionTimeoutMillis) { + long maxWaitForCapabilitiesMillis, long connectionTimeoutMillis) { this.address = address; this.nettyThreadGroup = nettyThreadGroup; this.maxWaitForCapabilitiesMillis = maxWaitForCapabilitiesMillis; @@ -129,8 +132,8 @@ public class ConfigPusher { final long deadlineNanos = pollingStartNanos + TimeUnit.MILLISECONDS.toNanos(maxWaitForCapabilitiesMillis); int attempt = 0; - String additionalHeader = NetconfMessageAdditionalHeader.toString("unknown", address.getAddress().getHostAddress(), - Integer.toString(address.getPort()), "tcp", Optional.of("persister")); + NetconfHelloMessageAdditionalHeader additionalHeader = new NetconfHelloMessageAdditionalHeader("unknown", address.getAddress().getHostAddress(), + Integer.toString(address.getPort()), "tcp", "persister"); Set latestCapabilities = null; while (System.nanoTime() < deadlineNanos) { @@ -224,13 +227,12 @@ public class ConfigPusher { NetconfMessage netconfMessage = netconfClient.sendMessage(request, NETCONF_SEND_ATTEMPTS, NETCONF_SEND_ATTEMPT_MS_DELAY); NetconfUtil.checkIsMessageOk(netconfMessage); return netconfMessage; - } catch (RuntimeException e) { // TODO: change NetconfClient#sendMessage to throw checked exceptions + } catch (RuntimeException | ExecutionException | InterruptedException | TimeoutException e) { logger.debug("Error while executing netconf transaction {} to {}", request, netconfClient, e); throw new IOException("Failed to execute netconf transaction", e); } } - // load editConfig.xml template, populate /rpc/edit-config/config with parameter private static NetconfMessage createEditConfigMessage(Element dataElement) { String editConfigResourcePath = "/netconfOp/editConfig.xml"; @@ -316,4 +318,4 @@ public class ConfigPusher { '}'; } } -} \ No newline at end of file +} diff --git a/opendaylight/netconf/netconf-api/src/main/java/org/opendaylight/controller/netconf/api/AbstractNetconfSession.java b/opendaylight/netconf/netconf-api/src/main/java/org/opendaylight/controller/netconf/api/AbstractNetconfSession.java new file mode 100644 index 0000000000..bd75c27dd6 --- /dev/null +++ b/opendaylight/netconf/netconf-api/src/main/java/org/opendaylight/controller/netconf/api/AbstractNetconfSession.java @@ -0,0 +1,86 @@ +/* + * 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.api; + +import io.netty.channel.Channel; +import io.netty.channel.ChannelFuture; + +import java.io.IOException; + +import org.opendaylight.protocol.framework.AbstractProtocolSession; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public abstract class AbstractNetconfSession> extends AbstractProtocolSession implements NetconfSession { + private static final Logger logger = LoggerFactory.getLogger(AbstractNetconfSession.class); + private final L sessionListener; + private final long sessionId; + private boolean up = false; + + protected 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()); + } + + protected abstract S thisInstance(); + + @Override + public void close() { + channel.close(); + up = false; + sessionListener.onSessionTerminated(thisInstance(), new NetconfTerminationReason("Session closed")); + } + + @Override + protected void handleMessage(NetconfMessage netconfMessage) { + logger.debug("handling incoming message"); + sessionListener.onMessage(thisInstance(), netconfMessage); + } + + @Override + public ChannelFuture sendMessage(NetconfMessage netconfMessage) { + return channel.writeAndFlush(netconfMessage); + } + + @Override + protected void endOfInput() { + logger.debug("Session {} end of input detected while session was in state {}", toString(), isUp() ? "up" + : "initialized"); + if (isUp()) { + this.sessionListener.onSessionDown(thisInstance(), new IOException("End of input detected. Close the session.")); + } + } + + @Override + protected void sessionUp() { + logger.debug("Session {} up", toString()); + sessionListener.onSessionUp(thisInstance()); + this.up = true; + } + + @Override + public String toString() { + final StringBuffer sb = new StringBuffer("ServerNetconfSession{"); + sb.append("sessionId=").append(sessionId); + sb.append('}'); + return sb.toString(); + } + + public final boolean isUp() { + return up; + } + + public final long getSessionId() { + return sessionId; + } +} + diff --git a/opendaylight/netconf/netconf-api/src/main/java/org/opendaylight/controller/netconf/api/NetconfDeserializerException.java b/opendaylight/netconf/netconf-api/src/main/java/org/opendaylight/controller/netconf/api/NetconfDeserializerException.java index f42db6938d..6e27b48978 100644 --- a/opendaylight/netconf/netconf-api/src/main/java/org/opendaylight/controller/netconf/api/NetconfDeserializerException.java +++ b/opendaylight/netconf/netconf-api/src/main/java/org/opendaylight/controller/netconf/api/NetconfDeserializerException.java @@ -8,14 +8,12 @@ package org.opendaylight.controller.netconf.api; -import org.opendaylight.protocol.framework.DeserializerException; - /** * This exception is thrown by * {@link NetconfSessionListener#onMessage(NetconfMessage)} to indicate fatal * communication problem after which the session should be closed. */ -public class NetconfDeserializerException extends DeserializerException { +public class NetconfDeserializerException extends Exception { private static final long serialVersionUID = 1L; public NetconfDeserializerException(final String message) { diff --git a/opendaylight/netconf/netconf-api/src/main/java/org/opendaylight/controller/netconf/api/NetconfDocumentedException.java b/opendaylight/netconf/netconf-api/src/main/java/org/opendaylight/controller/netconf/api/NetconfDocumentedException.java index 1107572df1..5a85e94257 100644 --- a/opendaylight/netconf/netconf-api/src/main/java/org/opendaylight/controller/netconf/api/NetconfDocumentedException.java +++ b/opendaylight/netconf/netconf-api/src/main/java/org/opendaylight/controller/netconf/api/NetconfDocumentedException.java @@ -11,13 +11,11 @@ package org.opendaylight.controller.netconf.api; import java.util.Collections; import java.util.Map; -import org.opendaylight.protocol.framework.DocumentedException; - /** * Checked exception to communicate an error that needs to be sent to the * netconf client. */ -public class NetconfDocumentedException extends DocumentedException { +public class NetconfDocumentedException extends Exception { private static final long serialVersionUID = 1L; diff --git a/opendaylight/netconf/netconf-api/src/main/java/org/opendaylight/controller/netconf/api/NetconfMessage.java b/opendaylight/netconf/netconf-api/src/main/java/org/opendaylight/controller/netconf/api/NetconfMessage.java index 7877843ccb..78586a3fec 100644 --- a/opendaylight/netconf/netconf-api/src/main/java/org/opendaylight/controller/netconf/api/NetconfMessage.java +++ b/opendaylight/netconf/netconf-api/src/main/java/org/opendaylight/controller/netconf/api/NetconfMessage.java @@ -10,34 +10,18 @@ package org.opendaylight.controller.netconf.api; import org.w3c.dom.Document; -import com.google.common.base.Optional; - /** * NetconfMessage represents a wrapper around org.w3c.dom.Document. Needed for * implementing ProtocolMessage interface. */ -public final class NetconfMessage { - - private static final long serialVersionUID = 462175939836367285L; - +public class NetconfMessage { private final Document doc; - private String additionalHeader; - public NetconfMessage(final Document doc) { - this(doc, null); - } - - public NetconfMessage(Document doc, String additionalHeader) { this.doc = doc; - this.additionalHeader = additionalHeader; } public Document getDocument() { return this.doc; } - - public Optional getAdditionalHeader() { - return additionalHeader== null ? Optional.absent() : Optional.of(additionalHeader); - } } diff --git a/opendaylight/netconf/netconf-api/src/main/java/org/opendaylight/controller/netconf/api/NetconfSession.java b/opendaylight/netconf/netconf-api/src/main/java/org/opendaylight/controller/netconf/api/NetconfSession.java index 6c747dbe24..e52e71ceea 100644 --- a/opendaylight/netconf/netconf-api/src/main/java/org/opendaylight/controller/netconf/api/NetconfSession.java +++ b/opendaylight/netconf/netconf-api/src/main/java/org/opendaylight/controller/netconf/api/NetconfSession.java @@ -7,74 +7,10 @@ */ package org.opendaylight.controller.netconf.api; -import io.netty.channel.Channel; -import org.opendaylight.protocol.framework.AbstractProtocolSession; -import org.opendaylight.protocol.framework.SessionListener; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import io.netty.channel.ChannelFuture; -import java.io.IOException; +import org.opendaylight.protocol.framework.ProtocolSession; -public abstract class NetconfSession extends AbstractProtocolSession { - protected final Channel channel; - private final SessionListener sessionListener; - private final long sessionId; - private boolean up = false; - private static final Logger logger = LoggerFactory.getLogger(NetconfSession.class); - - protected NetconfSession(SessionListener sessionListener, Channel channel, long sessionId) { - this.sessionListener = sessionListener; - this.channel = channel; - this.sessionId = sessionId; - logger.debug("Session {} created", toString()); - } - @Override - public void close() { - channel.close(); - up = false; - sessionListener.onSessionTerminated(this, new NetconfTerminationReason("Session closed")); - } - - @Override - protected void handleMessage(NetconfMessage netconfMessage) { - logger.debug("handling incoming message"); - sessionListener.onMessage(this, netconfMessage); - } - - public void sendMessage(NetconfMessage netconfMessage) { - channel.writeAndFlush(netconfMessage); - } - - @Override - protected void endOfInput() { - logger.debug("Session {} end of input detected while session was in state {}", toString(), isUp() ? "up" - : "initialized"); - if (isUp()) { - this.sessionListener.onSessionDown(this, new IOException("End of input detected. Close the session.")); - } - } - - @Override - protected void sessionUp() { - logger.debug("Session {} up", toString()); - sessionListener.onSessionUp(this); - this.up = true; - } - - @Override - public String toString() { - final StringBuffer sb = new StringBuffer("ServerNetconfSession{"); - sb.append("sessionId=").append(sessionId); - sb.append('}'); - return sb.toString(); - } - - public boolean isUp() { - return up; - } - - public long getSessionId() { - return sessionId; - } +public interface NetconfSession extends ProtocolSession { + ChannelFuture sendMessage(NetconfMessage message); } - diff --git a/opendaylight/netconf/netconf-api/src/main/java/org/opendaylight/controller/netconf/api/NetconfSessionListener.java b/opendaylight/netconf/netconf-api/src/main/java/org/opendaylight/controller/netconf/api/NetconfSessionListener.java index 54cb471604..0f7869d97a 100644 --- a/opendaylight/netconf/netconf-api/src/main/java/org/opendaylight/controller/netconf/api/NetconfSessionListener.java +++ b/opendaylight/netconf/netconf-api/src/main/java/org/opendaylight/controller/netconf/api/NetconfSessionListener.java @@ -10,7 +10,6 @@ package org.opendaylight.controller.netconf.api; import org.opendaylight.protocol.framework.SessionListener; -public interface NetconfSessionListener extends - SessionListener { +public interface NetconfSessionListener extends SessionListener { } diff --git a/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/AbstractNetconfClientNotifySessionListener.java b/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/AbstractNetconfClientNotifySessionListener.java index 48109d1353..6ae966d1f7 100644 --- a/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/AbstractNetconfClientNotifySessionListener.java +++ b/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/AbstractNetconfClientNotifySessionListener.java @@ -15,7 +15,7 @@ import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants; /** * Class extending {@link NetconfClientSessionListener} to provide notification capability. */ -public abstract class AbstractNetconfClientNotifySessionListener extends NetconfClientSessionListener { +public abstract class AbstractNetconfClientNotifySessionListener extends SimpleNetconfClientSessionListener { /* * Maybe some capabilities could be expressed as internal NetconfClientSessionListener handlers. * It would enable NetconfClient functionality to be extended by using namespace handlers. @@ -31,7 +31,7 @@ public abstract class AbstractNetconfClientNotifySessionListener extends Netconf * @param message {@see NetconfClientSessionListener#onMessage(NetconfClientSession, NetconfMessage)} */ @Override - public final synchronized void onMessage(NetconfClientSession session, NetconfMessage message) { + public final void onMessage(NetconfClientSession session, NetconfMessage message) { if (isNotification(message)) { onNotification(session, message); } else { diff --git a/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClient.java b/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClient.java index 4fcad2cbd6..4cdca208bc 100644 --- a/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClient.java +++ b/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClient.java @@ -8,17 +8,8 @@ package org.opendaylight.controller.netconf.client; -import com.google.common.base.Preconditions; -import com.google.common.base.Stopwatch; -import com.google.common.collect.Sets; import io.netty.util.concurrent.Future; import io.netty.util.concurrent.GlobalEventExecutor; -import org.opendaylight.controller.netconf.api.NetconfMessage; -import org.opendaylight.protocol.framework.NeverReconnectStrategy; -import org.opendaylight.protocol.framework.ReconnectStrategy; -import org.opendaylight.protocol.framework.TimedReconnectStrategy; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import java.io.Closeable; import java.io.IOException; @@ -27,7 +18,23 @@ import java.util.Set; import java.util.concurrent.CancellationException; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import org.opendaylight.controller.netconf.api.NetconfMessage; +import org.opendaylight.protocol.framework.NeverReconnectStrategy; +import org.opendaylight.protocol.framework.ReconnectStrategy; +import org.opendaylight.protocol.framework.TimedReconnectStrategy; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.Preconditions; +import com.google.common.base.Stopwatch; +import com.google.common.collect.Sets; + +/** + * @deprecated Use {@link NetconfClientDispatcher.createClient()} or {@link NetconfClientDispatcher.createReconnectingClient()} instead. + */ +@Deprecated public class NetconfClient implements Closeable { private static final Logger logger = LoggerFactory.getLogger(NetconfClient.class); @@ -50,7 +57,7 @@ public class NetconfClient implements Closeable { private NetconfClient(String clientLabelForLogging, InetSocketAddress address, ReconnectStrategy strat, NetconfClientDispatcher netconfClientDispatcher) throws InterruptedException { this.label = clientLabelForLogging; dispatch = netconfClientDispatcher; - sessionListener = new NetconfClientSessionListener(); + sessionListener = new SimpleNetconfClientSessionListener(); Future clientFuture = dispatch.createClient(address, sessionListener, strat); this.address = address; clientSession = get(clientFuture); @@ -61,18 +68,19 @@ public class NetconfClient implements Closeable { try { return clientFuture.get(); } catch (CancellationException e) { - throw new RuntimeException("Netconf client interrupted", e); + throw new RuntimeException("Cancelling " + this, e); } catch (ExecutionException e) { - throw new IllegalStateException("Unable to create netconf client", e); + throw new IllegalStateException("Unable to create " + this, e); } } - public static NetconfClient clientFor(String clientLabelForLogging, InetSocketAddress address, ReconnectStrategy strat, NetconfClientDispatcher netconfClientDispatcher) throws InterruptedException { - return new NetconfClient(clientLabelForLogging,address,strat,netconfClientDispatcher); + public static NetconfClient clientFor(String clientLabelForLogging, InetSocketAddress address, ReconnectStrategy strategy, NetconfClientDispatcher netconfClientDispatcher) throws InterruptedException { + return new NetconfClient(clientLabelForLogging,address,strategy,netconfClientDispatcher); } - public static NetconfClient clientFor(String clientLabelForLogging, InetSocketAddress address, ReconnectStrategy strat, NetconfClientDispatcher netconfClientDispatcher,NetconfClientSessionListener listener) throws InterruptedException { - return new NetconfClient(clientLabelForLogging,address,strat,netconfClientDispatcher,listener); + public static NetconfClient clientFor(String clientLabelForLogging, InetSocketAddress address, + ReconnectStrategy strategy, NetconfClientDispatcher netconfClientDispatcher, NetconfClientSessionListener listener) throws InterruptedException { + return new NetconfClient(clientLabelForLogging,address,strategy,netconfClientDispatcher,listener); } public NetconfClient(String clientLabelForLogging, InetSocketAddress address, int connectTimeoutMs, @@ -87,36 +95,42 @@ public class NetconfClient implements Closeable { DEFAULT_CONNECT_TIMEOUT), netconfClientDispatcher); } - public NetconfClient(String clientLabelForLogging, InetSocketAddress address, ReconnectStrategy strat, + public NetconfClient(String clientLabelForLogging, InetSocketAddress address, ReconnectStrategy strategy, NetconfClientDispatcher netconfClientDispatcher, NetconfClientSessionListener listener) throws InterruptedException{ this.label = clientLabelForLogging; dispatch = netconfClientDispatcher; sessionListener = listener; - Future clientFuture = dispatch.createClient(address, sessionListener, strat); + Future clientFuture = dispatch.createClient(address, sessionListener, strategy); this.address = address; clientSession = get(clientFuture); this.sessionId = clientSession.getSessionId(); } - public NetconfMessage sendMessage(NetconfMessage message) { + public Future sendRequest(NetconfMessage message) { + return ((SimpleNetconfClientSessionListener)sessionListener).sendRequest(message); + } + + /** + * @deprecated Use {@link sendRequest} instead + */ + @Deprecated + public NetconfMessage sendMessage(NetconfMessage message) throws ExecutionException, InterruptedException, TimeoutException { return sendMessage(message, 5, 1000); } - public NetconfMessage sendMessage(NetconfMessage message, int attempts, int attemptMsDelay) { - Stopwatch stopwatch = new Stopwatch().start(); - Preconditions.checkState(clientSession.isUp(), "Session was not up yet"); + /** + * @deprecated Use {@link sendRequest} instead + */ + @Deprecated + public NetconfMessage sendMessage(NetconfMessage message, int attempts, int attemptMsDelay) throws ExecutionException, InterruptedException, TimeoutException { //logger.debug("Sending message: {}",XmlUtil.toString(message.getDocument())); - clientSession.sendMessage(message); + final Stopwatch stopwatch = new Stopwatch().start(); + try { - return sessionListener.getLastMessage(attempts, attemptMsDelay); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - throw new RuntimeException(this + " Cannot read message from " + address, e); - } catch (IllegalStateException e) { - throw new IllegalStateException(this + " Cannot read message from " + address, e); + return sendRequest(message).get(attempts * attemptMsDelay, TimeUnit.MILLISECONDS); } finally { stopwatch.stop(); - logger.debug("Total time spent waiting for response {} ms", stopwatch.elapsed(TimeUnit.MILLISECONDS)); + logger.debug("Total time spent waiting for response from {}: {} ms", address, stopwatch.elapsed(TimeUnit.MILLISECONDS)); } } diff --git a/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientDispatcher.java b/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientDispatcher.java index 1228a84a8a..43664b3233 100644 --- a/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientDispatcher.java +++ b/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientDispatcher.java @@ -8,43 +8,47 @@ package org.opendaylight.controller.netconf.client; -import com.google.common.base.Optional; import io.netty.channel.EventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.util.HashedWheelTimer; import io.netty.util.concurrent.Future; import io.netty.util.concurrent.Promise; -import org.opendaylight.controller.netconf.api.NetconfMessage; -import org.opendaylight.controller.netconf.api.NetconfSession; -import org.opendaylight.controller.netconf.api.NetconfTerminationReason; + +import java.io.Closeable; +import java.net.InetSocketAddress; + import org.opendaylight.controller.netconf.util.AbstractChannelInitializer; +import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessageAdditionalHeader; import org.opendaylight.protocol.framework.AbstractDispatcher; import org.opendaylight.protocol.framework.ReconnectStrategy; -import org.opendaylight.protocol.framework.SessionListener; +import org.opendaylight.protocol.framework.ReconnectStrategyFactory; import org.opendaylight.protocol.framework.SessionListenerFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.Closeable; -import java.net.InetSocketAddress; +import com.google.common.base.Optional; public class NetconfClientDispatcher extends AbstractDispatcher implements Closeable { - private static final Logger logger = LoggerFactory.getLogger(NetconfClient.class); + private static final Logger logger = LoggerFactory.getLogger(NetconfClientDispatcher.class); - private final NetconfClientSessionNegotiatorFactory negotatorFactory; + private final NetconfClientSessionNegotiatorFactory negotiatorFactory; private final HashedWheelTimer timer; - public NetconfClientDispatcher(EventLoopGroup bossGroup, EventLoopGroup workerGroup, long clientConnectionTimeoutMillis) { + public NetconfClientDispatcher(EventLoopGroup bossGroup, EventLoopGroup workerGroup, + long clientConnectionTimeoutMillis) { super(bossGroup, workerGroup); timer = new HashedWheelTimer(); - this.negotatorFactory = new NetconfClientSessionNegotiatorFactory(timer, Optional.absent(), clientConnectionTimeoutMillis); + this.negotiatorFactory = new NetconfClientSessionNegotiatorFactory(timer, + Optional. absent(), clientConnectionTimeoutMillis); } - public NetconfClientDispatcher(EventLoopGroup bossGroup, EventLoopGroup workerGroup, String additionalHeader, long connectionTimeoutMillis) { + public NetconfClientDispatcher(EventLoopGroup bossGroup, EventLoopGroup workerGroup, + NetconfHelloMessageAdditionalHeader additionalHeader, long connectionTimeoutMillis) { super(bossGroup, workerGroup); timer = new HashedWheelTimer(); - this.negotatorFactory = new NetconfClientSessionNegotiatorFactory(timer, Optional.of(additionalHeader), connectionTimeoutMillis); + this.negotiatorFactory = new NetconfClientSessionNegotiatorFactory(timer, Optional.of(additionalHeader), + connectionTimeoutMillis); } public Future createClient(InetSocketAddress address, @@ -58,38 +62,54 @@ public class NetconfClientDispatcher extends AbstractDispatcher promise) { - new ClientChannelInitializer( negotatorFactory, sessionListener).initialize(ch, promise); + new ClientChannelInitializer(negotiatorFactory, sessionListener).initialize(ch, promise); } }); } - private static class ClientChannelInitializer extends AbstractChannelInitializer { + public Future createReconnectingClient(final InetSocketAddress address, + final NetconfClientSessionListener listener, + final ReconnectStrategyFactory connectStrategyFactory, final ReconnectStrategy reestablishStrategy) { + final ClientChannelInitializer init = new ClientChannelInitializer(negotiatorFactory, listener); + + return super.createReconnectingClient(address, connectStrategyFactory, reestablishStrategy, + new PipelineInitializer() { + @Override + public void initializeChannel(final SocketChannel ch, final Promise promise) { + init.initialize(ch, promise); + } + }); + } + + private static class ClientChannelInitializer extends AbstractChannelInitializer { private final NetconfClientSessionNegotiatorFactory negotiatorFactory; private final NetconfClientSessionListener sessionListener; private ClientChannelInitializer(NetconfClientSessionNegotiatorFactory negotiatorFactory, - NetconfClientSessionListener sessionListener) { + NetconfClientSessionListener sessionListener) { this.negotiatorFactory = negotiatorFactory; this.sessionListener = sessionListener; } @Override - public void initialize(SocketChannel ch, Promise promise) { + public void initialize(SocketChannel ch, Promise promise) { super.initialize(ch,promise); } @Override - protected void initializeAfterDecoder(SocketChannel ch, Promise promise) { - ch.pipeline().addLast("negotiator", negotiatorFactory.getSessionNegotiator(new SessionListenerFactory() { - @Override - public SessionListener getSessionListener() { - return sessionListener; - } - }, ch, promise)); + protected void initializeSessionNegotiator(SocketChannel ch, Promise promise) { + ch.pipeline().addAfter(NETCONF_MESSAGE_DECODER, AbstractChannelInitializer.NETCONF_SESSION_NEGOTIATOR, + negotiatorFactory.getSessionNegotiator( + new SessionListenerFactory() { + @Override + public NetconfClientSessionListener getSessionListener() { + return sessionListener; + } + }, ch, promise)); } - } + @Override public void close() { try { diff --git a/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientSession.java b/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientSession.java index c57487f70b..2d07dd5833 100644 --- a/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientSession.java +++ b/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientSession.java @@ -9,19 +9,19 @@ package org.opendaylight.controller.netconf.client; import io.netty.channel.Channel; -import org.opendaylight.controller.netconf.api.NetconfSession; -import org.opendaylight.protocol.framework.SessionListener; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import java.util.Collection; -public class NetconfClientSession extends NetconfSession { +import org.opendaylight.controller.netconf.api.AbstractNetconfSession; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public final class NetconfClientSession extends AbstractNetconfSession { private static final Logger logger = LoggerFactory.getLogger(NetconfClientSession.class); private final Collection capabilities; - public NetconfClientSession(SessionListener sessionListener, Channel channel, long sessionId, + public NetconfClientSession(NetconfClientSessionListener sessionListener, Channel channel, long sessionId, Collection capabilities) { super(sessionListener,channel,sessionId); this.capabilities = capabilities; @@ -32,4 +32,8 @@ public class NetconfClientSession extends NetconfSession { return capabilities; } + @Override + protected NetconfClientSession thisInstance() { + return this; + } } diff --git a/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientSessionListener.java b/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientSessionListener.java index d3c1b22c84..21be3a8cab 100644 --- a/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientSessionListener.java +++ b/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientSessionListener.java @@ -1,75 +1,14 @@ /* - * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html */ - package org.opendaylight.controller.netconf.client; -import com.google.common.base.Preconditions; -import com.google.common.collect.Lists; -import org.opendaylight.controller.netconf.api.NetconfMessage; -import org.opendaylight.controller.netconf.api.NetconfTerminationReason; -import org.opendaylight.protocol.framework.SessionListener; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.List; -import java.util.concurrent.atomic.AtomicBoolean; - -public class NetconfClientSessionListener implements - SessionListener { - - private static final Logger logger = LoggerFactory.getLogger(NetconfClientSessionListener.class); - private AtomicBoolean up = new AtomicBoolean(false); - - @Override - public void onSessionUp(NetconfClientSession clientSession) { - up.set(true); - } - - @Override - public void onSessionDown(NetconfClientSession clientSession, Exception e) { - logger.debug("Client Session {} down, reason: {}", clientSession, e.getMessage()); - up.set(false); - } - - @Override - public void onSessionTerminated(NetconfClientSession clientSession, - NetconfTerminationReason netconfTerminationReason) { - logger.debug("Client Session {} terminated, reason: {}", clientSession, - netconfTerminationReason.getErrorMessage()); - up.set(false); - } - - @Override - public synchronized void onMessage(NetconfClientSession session, NetconfMessage message) { - synchronized (messages) { - this.messages.add(message); - } - } - - private int lastReadMessage = -1; - private List messages = Lists.newArrayList(); - - public NetconfMessage getLastMessage(int attempts, int attemptMsDelay) throws InterruptedException { - Preconditions.checkState(up.get(), "Session was not up yet"); - - for (int i = 0; i < attempts; i++) { - synchronized (messages) { - if (messages.size() - 1 > lastReadMessage) { - lastReadMessage++; - return messages.get(lastReadMessage); - } - } +import org.opendaylight.controller.netconf.api.NetconfSessionListener; - if (up.get() == false) - throw new IllegalStateException("Session ended while trying to read message"); - Thread.sleep(attemptMsDelay); - } +public interface NetconfClientSessionListener extends NetconfSessionListener { - throw new IllegalStateException("No netconf message to read"); - } } diff --git a/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientSessionNegotiator.java b/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientSessionNegotiator.java index 100b98c15a..c742bafe5e 100644 --- a/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientSessionNegotiator.java +++ b/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientSessionNegotiator.java @@ -8,33 +8,35 @@ package org.opendaylight.controller.netconf.client; -import com.google.common.base.Function; -import com.google.common.collect.Collections2; -import io.netty.channel.Channel; -import io.netty.util.Timer; -import io.netty.util.concurrent.Promise; -import org.opendaylight.controller.netconf.api.NetconfMessage; +import java.util.Collection; +import java.util.List; + +import javax.annotation.Nullable; +import javax.xml.xpath.XPathConstants; +import javax.xml.xpath.XPathExpression; + import org.opendaylight.controller.netconf.api.NetconfSessionPreferences; import org.opendaylight.controller.netconf.util.AbstractNetconfSessionNegotiator; +import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessage; import org.opendaylight.controller.netconf.util.xml.XMLNetconfUtil; import org.opendaylight.controller.netconf.util.xml.XmlElement; import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants; import org.opendaylight.controller.netconf.util.xml.XmlUtil; -import org.opendaylight.protocol.framework.SessionListener; import org.w3c.dom.Document; import org.w3c.dom.Node; -import javax.annotation.Nullable; -import javax.xml.xpath.XPathConstants; -import javax.xml.xpath.XPathExpression; -import java.util.Collection; -import java.util.List; +import com.google.common.base.Function; +import com.google.common.collect.Collections2; + +import io.netty.channel.Channel; +import io.netty.util.Timer; +import io.netty.util.concurrent.Promise; public class NetconfClientSessionNegotiator extends - AbstractNetconfSessionNegotiator { + AbstractNetconfSessionNegotiator { protected NetconfClientSessionNegotiator(NetconfSessionPreferences sessionPreferences, - Promise promise, Channel channel, Timer timer, SessionListener sessionListener, + Promise promise, Channel channel, Timer timer, NetconfClientSessionListener sessionListener, long connectionTimeoutMillis) { super(sessionPreferences, promise, channel, timer, sessionListener, connectionTimeoutMillis); } @@ -69,7 +71,7 @@ public class NetconfClientSessionNegotiator extends } @Override - protected NetconfClientSession getSession(SessionListener sessionListener, Channel channel, NetconfMessage message) { + protected NetconfClientSession getSession(NetconfClientSessionListener sessionListener, Channel channel, NetconfHelloMessage message) { return new NetconfClientSession(sessionListener, channel, extractSessionId(message.getDocument()), getCapabilities(message.getDocument())); } diff --git a/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientSessionNegotiatorFactory.java b/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientSessionNegotiatorFactory.java index db6c024e5a..bb372b3aff 100644 --- a/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientSessionNegotiatorFactory.java +++ b/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientSessionNegotiatorFactory.java @@ -8,31 +8,34 @@ package org.opendaylight.controller.netconf.client; -import com.google.common.base.Optional; -import com.google.common.base.Preconditions; import io.netty.channel.Channel; import io.netty.util.Timer; import io.netty.util.concurrent.Promise; + +import java.io.IOException; +import java.io.InputStream; + import org.opendaylight.controller.netconf.api.NetconfMessage; import org.opendaylight.controller.netconf.api.NetconfSessionPreferences; +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.opendaylight.protocol.framework.SessionListenerFactory; import org.opendaylight.protocol.framework.SessionNegotiator; import org.opendaylight.protocol.framework.SessionNegotiatorFactory; import org.xml.sax.SAXException; -import java.io.IOException; -import java.io.InputStream; - -public class NetconfClientSessionNegotiatorFactory implements SessionNegotiatorFactory { +import com.google.common.base.Optional; +import com.google.common.base.Preconditions; - private final Timer timer; +public class NetconfClientSessionNegotiatorFactory implements SessionNegotiatorFactory { - private final Optional additionalHeader; + private final Optional additionalHeader; private final long connectionTimeoutMillis; + private final Timer timer; - public NetconfClientSessionNegotiatorFactory(Timer timer, Optional additionalHeader, long connectionTimeoutMillis) { - this.timer = timer; + public NetconfClientSessionNegotiatorFactory(Timer timer, Optional additionalHeader, long connectionTimeoutMillis) { + this.timer = Preconditions.checkNotNull(timer); this.additionalHeader = additionalHeader; this.connectionTimeoutMillis = connectionTimeoutMillis; } @@ -48,16 +51,18 @@ public class NetconfClientSessionNegotiatorFactory implements SessionNegotiatorF } @Override - public SessionNegotiator getSessionNegotiator(SessionListenerFactory sessionListenerFactory, Channel channel, - Promise promise) { + public SessionNegotiator getSessionNegotiator(SessionListenerFactory sessionListenerFactory, Channel channel, + Promise promise) { // Hello message needs to be recreated every time NetconfMessage helloMessage = loadHelloMessageTemplate(); + if(this.additionalHeader.isPresent()) { - helloMessage = new NetconfMessage(helloMessage.getDocument(), additionalHeader.get()); - } + helloMessage = new NetconfHelloMessage(helloMessage.getDocument(), additionalHeader.get()); + } else + helloMessage = new NetconfHelloMessage(helloMessage.getDocument()); + NetconfSessionPreferences proposal = new NetconfSessionPreferences(helloMessage); return new NetconfClientSessionNegotiator(proposal, promise, channel, timer, sessionListenerFactory.getSessionListener(), connectionTimeoutMillis); } - } diff --git a/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfSshClientDispatcher.java b/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfSshClientDispatcher.java index 06239b2bfd..5b82ff2215 100644 --- a/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfSshClientDispatcher.java +++ b/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfSshClientDispatcher.java @@ -8,68 +8,80 @@ package org.opendaylight.controller.netconf.client; -import com.google.common.base.Optional; -import io.netty.channel.ChannelHandler; import io.netty.channel.EventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.util.HashedWheelTimer; import io.netty.util.concurrent.Future; import io.netty.util.concurrent.Promise; -import org.opendaylight.controller.netconf.api.NetconfMessage; -import org.opendaylight.controller.netconf.api.NetconfSession; -import org.opendaylight.controller.netconf.api.NetconfTerminationReason; + +import java.io.IOException; +import java.net.InetSocketAddress; + import org.opendaylight.controller.netconf.util.AbstractChannelInitializer; import org.opendaylight.controller.netconf.util.handler.ssh.SshHandler; import org.opendaylight.controller.netconf.util.handler.ssh.authentication.AuthenticationHandler; import org.opendaylight.controller.netconf.util.handler.ssh.client.Invoker; -import org.opendaylight.controller.netconf.util.messages.NetconfMessageFactory; -import org.opendaylight.protocol.framework.ProtocolHandlerFactory; -import org.opendaylight.protocol.framework.ProtocolMessageDecoder; -import org.opendaylight.protocol.framework.ProtocolMessageEncoder; +import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessageAdditionalHeader; import org.opendaylight.protocol.framework.ReconnectStrategy; -import org.opendaylight.protocol.framework.SessionListener; +import org.opendaylight.protocol.framework.ReconnectStrategyFactory; import org.opendaylight.protocol.framework.SessionListenerFactory; -import java.io.IOException; -import java.net.InetSocketAddress; +import com.google.common.base.Optional; public class NetconfSshClientDispatcher extends NetconfClientDispatcher { - private AuthenticationHandler authHandler; - private HashedWheelTimer timer; - private NetconfClientSessionNegotiatorFactory negotatorFactory; + private final AuthenticationHandler authHandler; + private final HashedWheelTimer timer; + private final NetconfClientSessionNegotiatorFactory negotiatorFactory; public NetconfSshClientDispatcher(AuthenticationHandler authHandler, EventLoopGroup bossGroup, EventLoopGroup workerGroup, long connectionTimeoutMillis) { super(bossGroup, workerGroup, connectionTimeoutMillis); this.authHandler = authHandler; this.timer = new HashedWheelTimer(); - this.negotatorFactory = new NetconfClientSessionNegotiatorFactory(timer, Optional.absent(), connectionTimeoutMillis); + this.negotiatorFactory = new NetconfClientSessionNegotiatorFactory(timer, + Optional. absent(), connectionTimeoutMillis); } public NetconfSshClientDispatcher(AuthenticationHandler authHandler, EventLoopGroup bossGroup, - EventLoopGroup workerGroup, String additionalHeader, long socketTimeoutMillis) { + EventLoopGroup workerGroup, NetconfHelloMessageAdditionalHeader additionalHeader, long socketTimeoutMillis) { super(bossGroup, workerGroup, additionalHeader, socketTimeoutMillis); this.authHandler = authHandler; this.timer = new HashedWheelTimer(); - this.negotatorFactory = new NetconfClientSessionNegotiatorFactory(timer, Optional.of(additionalHeader), socketTimeoutMillis); + this.negotiatorFactory = new NetconfClientSessionNegotiatorFactory(timer, Optional.of(additionalHeader), + socketTimeoutMillis); } + @Override public Future createClient(InetSocketAddress address, final NetconfClientSessionListener sessionListener, ReconnectStrategy strat) { return super.createClient(address, strat, new PipelineInitializer() { @Override public void initializeChannel(SocketChannel arg0, Promise arg1) { - new NetconfSshClientInitializer(authHandler, negotatorFactory, sessionListener).initialize(arg0, arg1); + new NetconfSshClientInitializer(authHandler, negotiatorFactory, sessionListener).initialize(arg0, arg1); } }); } - private static final class NetconfSshClientInitializer extends AbstractChannelInitializer { + @Override + public Future createReconnectingClient(final InetSocketAddress address, + final NetconfClientSessionListener listener, + final ReconnectStrategyFactory connectStrategyFactory, final ReconnectStrategy reestablishStrategy) { + final NetconfSshClientInitializer init = new NetconfSshClientInitializer(authHandler, negotiatorFactory, listener); + + return super.createReconnectingClient(address, connectStrategyFactory, reestablishStrategy, + new PipelineInitializer() { + @Override + public void initializeChannel(final SocketChannel ch, final Promise promise) { + init.initialize(ch, promise); + } + }); + } + + private static final class NetconfSshClientInitializer extends AbstractChannelInitializer { - private final NetconfHandlerFactory handlerFactory; private final AuthenticationHandler authenticationHandler; private final NetconfClientSessionNegotiatorFactory negotiatorFactory; private final NetconfClientSessionListener sessionListener; @@ -77,14 +89,13 @@ public class NetconfSshClientDispatcher extends NetconfClientDispatcher { public NetconfSshClientInitializer(AuthenticationHandler authHandler, NetconfClientSessionNegotiatorFactory negotiatorFactory, final NetconfClientSessionListener sessionListener) { - this.handlerFactory = new NetconfHandlerFactory(new NetconfMessageFactory()); this.authenticationHandler = authHandler; this.negotiatorFactory = negotiatorFactory; this.sessionListener = sessionListener; } @Override - public void initialize(SocketChannel ch, Promise promise) { + public void initialize(SocketChannel ch, Promise promise) { try { Invoker invoker = Invoker.subsystem("netconf"); ch.pipeline().addFirst(new SshHandler(authenticationHandler, invoker)); @@ -95,31 +106,15 @@ public class NetconfSshClientDispatcher extends NetconfClientDispatcher { } @Override - protected void initializeAfterDecoder(SocketChannel ch, Promise promise) { - ch.pipeline().addLast("negotiator", negotiatorFactory.getSessionNegotiator(new SessionListenerFactory() { + protected void initializeSessionNegotiator(SocketChannel ch, + Promise promise) { + ch.pipeline().addAfter(NETCONF_MESSAGE_DECODER, AbstractChannelInitializer.NETCONF_SESSION_NEGOTIATOR, + negotiatorFactory.getSessionNegotiator(new SessionListenerFactory() { @Override - public SessionListener getSessionListener() { + public NetconfClientSessionListener getSessionListener() { return sessionListener; } }, ch, promise)); - - } - } - - private static final class NetconfHandlerFactory extends ProtocolHandlerFactory { - - public NetconfHandlerFactory(final NetconfMessageFactory msgFactory) { - super(msgFactory); - } - - @Override - public ChannelHandler[] getEncoders() { - return new ChannelHandler[] { new ProtocolMessageEncoder(this.msgFactory) }; - } - - @Override - public ChannelHandler[] getDecoders() { - return new ChannelHandler[] { new ProtocolMessageDecoder(this.msgFactory) }; } } } diff --git a/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/SimpleNetconfClientSessionListener.java b/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/SimpleNetconfClientSessionListener.java new file mode 100644 index 0000000000..e96161c29a --- /dev/null +++ b/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/SimpleNetconfClientSessionListener.java @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.netconf.client; + +import io.netty.util.concurrent.Future; +import io.netty.util.concurrent.GlobalEventExecutor; +import io.netty.util.concurrent.Promise; + +import java.util.ArrayDeque; +import java.util.Queue; + +import javax.annotation.concurrent.GuardedBy; + +import org.opendaylight.controller.netconf.api.NetconfMessage; +import org.opendaylight.controller.netconf.api.NetconfTerminationReason; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.Preconditions; + +public class SimpleNetconfClientSessionListener implements NetconfClientSessionListener { + private static final class RequestEntry { + final Promise promise; + final NetconfMessage request; + + public RequestEntry(Promise future, NetconfMessage request) { + this.promise = Preconditions.checkNotNull(future); + this.request = Preconditions.checkNotNull(request); + } + } + + private static final Logger logger = LoggerFactory.getLogger(SimpleNetconfClientSessionListener.class); + + @GuardedBy("this") + private final Queue requests = new ArrayDeque<>(); + + @GuardedBy("this") + private NetconfClientSession clientSession; + + @GuardedBy("this") + private void dispatchRequest() { + while (!requests.isEmpty()) { + final RequestEntry e = requests.peek(); + if (e.promise.setUncancellable()) { + logger.debug("Sending message {}", e.request); + clientSession.sendMessage(e.request); + break; + } + + logger.debug("Message {} has been cancelled, skipping it", e.request); + requests.poll(); + } + } + + @Override + public final synchronized void onSessionUp(NetconfClientSession clientSession) { + this.clientSession = Preconditions.checkNotNull(clientSession); + logger.debug("Client session {} went up", clientSession); + dispatchRequest(); + } + + private synchronized void tearDown(final Exception cause) { + final RequestEntry e = requests.poll(); + if (e != null) { + e.promise.setFailure(cause); + } + + this.clientSession = null; + } + + @Override + public final void onSessionDown(NetconfClientSession clientSession, Exception e) { + logger.debug("Client Session {} went down unexpectedly", clientSession, e); + tearDown(e); + } + + @Override + public final void onSessionTerminated(NetconfClientSession clientSession, + NetconfTerminationReason netconfTerminationReason) { + logger.debug("Client Session {} terminated, reason: {}", clientSession, + netconfTerminationReason.getErrorMessage()); + tearDown(new RuntimeException(netconfTerminationReason.getErrorMessage())); + } + + @Override + public synchronized void onMessage(NetconfClientSession session, NetconfMessage message) { + logger.debug("New message arrived: {}", message); + + final RequestEntry e = requests.poll(); + if (e != null) { + e.promise.setSuccess(message); + dispatchRequest(); + } else { + logger.info("Ignoring unsolicited message {}", message); + } + } + + final synchronized Future sendRequest(NetconfMessage message) { + final RequestEntry req = new RequestEntry(GlobalEventExecutor.INSTANCE.newPromise(), message); + + requests.add(req); + if (clientSession != null) { + dispatchRequest(); + } + + return req.promise; + } +} diff --git a/opendaylight/netconf/netconf-client/src/test/java/org/opendaylight/controller/netconf/client/SSHNetconfClientLiveTest.java b/opendaylight/netconf/netconf-client/src/test/java/org/opendaylight/controller/netconf/client/SSHNetconfClientLiveTest.java index a3cc10417e..1357201f57 100644 --- a/opendaylight/netconf/netconf-client/src/test/java/org/opendaylight/controller/netconf/client/SSHNetconfClientLiveTest.java +++ b/opendaylight/netconf/netconf-client/src/test/java/org/opendaylight/controller/netconf/client/SSHNetconfClientLiveTest.java @@ -12,38 +12,78 @@ import io.netty.channel.nio.NioEventLoopGroup; import org.junit.Before; import org.junit.Ignore; import org.junit.Test; -import org.opendaylight.controller.netconf.api.NetconfMessage; -import org.opendaylight.controller.netconf.util.NetconfUtil; import org.opendaylight.controller.netconf.util.handler.ssh.authentication.LoginPassword; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import java.io.IOException; import java.net.InetSocketAddress; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; @Ignore public class SSHNetconfClientLiveTest { + private static final Logger logger = LoggerFactory.getLogger(SSHNetconfClientLiveTest.class); NioEventLoopGroup nettyThreadgroup; NetconfSshClientDispatcher netconfClientDispatcher; + InetSocketAddress address; + final int connectionAttempts = 10, attemptMsTimeout = 1000; + final int connectionTimeoutMillis = 20000; @Before public void setUp() { nettyThreadgroup = new NioEventLoopGroup(); + netconfClientDispatcher = new NetconfSshClientDispatcher(new LoginPassword( System.getProperty("username"), System.getProperty("password")), - nettyThreadgroup, nettyThreadgroup, 5000); + nettyThreadgroup, nettyThreadgroup, connectionTimeoutMillis); + + address = new InetSocketAddress(System.getProperty("host"), Integer.parseInt(System.getProperty("port"))); } + @Ignore @Test public void test() throws Exception { - InetSocketAddress address = new InetSocketAddress(System.getProperty("host"), 830); - int connectionAttempts = 10, attemptMsTimeout = 1000; + //runnable.run(); + } - NetconfClient netconfClient = new NetconfClient("client", address, connectionAttempts, - attemptMsTimeout, netconfClientDispatcher); + @Test + public void testInExecutor() throws Exception { + int threads = 4; + ExecutorService executorService = Executors.newFixedThreadPool(threads); + try { + for (int i= 0;i< threads;i++) { + InetSocketAddress address = new InetSocketAddress(System.getProperty("host"), + Integer.parseInt(System.getProperty("port"))); + NetconfRunnable runnable = new NetconfRunnable(address); + executorService.execute(runnable); + } + executorService.shutdown(); + executorService.awaitTermination(1, TimeUnit.MINUTES); - netconfClient.getCapabilities(); - NetconfMessage netconfMessage = NetconfUtil.createMessage(getClass().getResourceAsStream("/get_schema.xml")); - NetconfMessage response = netconfClient.sendMessage(netconfMessage); - NetconfUtil.checkIsMessageOk(response); + } finally { + executorService.shutdownNow(); + } } + + class NetconfRunnable implements Runnable { + private final InetSocketAddress address; + + NetconfRunnable(InetSocketAddress address) { + this.address = address; + } + + @Override + public void run() { + try (NetconfClient netconfClient = new NetconfClient(address.toString(), address, connectionAttempts, + attemptMsTimeout, netconfClientDispatcher);) { + logger.info("OK {}", address); + } catch (InterruptedException | IOException e) { + logger.error("Failed {}", address, e); + } + } + }; } diff --git a/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/NetconfServerDispatcher.java b/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/NetconfServerDispatcher.java index 7c5bd0cb21..ee9009762e 100644 --- a/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/NetconfServerDispatcher.java +++ b/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/NetconfServerDispatcher.java @@ -12,14 +12,14 @@ import io.netty.channel.ChannelFuture; import io.netty.channel.EventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.util.concurrent.Promise; -import org.opendaylight.controller.netconf.api.NetconfSession; + +import java.net.InetSocketAddress; + import org.opendaylight.controller.netconf.impl.util.DeserializerExceptionHandler; import org.opendaylight.controller.netconf.util.AbstractChannelInitializer; import org.opendaylight.protocol.framework.AbstractDispatcher; -import java.net.InetSocketAddress; - -public class NetconfServerDispatcher extends AbstractDispatcher { +public class NetconfServerDispatcher extends AbstractDispatcher { private final ServerChannelInitializer initializer; @@ -31,15 +31,17 @@ public class NetconfServerDispatcher extends AbstractDispatcher() { + return super.createServer(address, new PipelineInitializer() { @Override - public void initializeChannel(final SocketChannel ch, final Promise promise) { + public void initializeChannel(final SocketChannel ch, final Promise promise) { initializer.initialize(ch, promise); } }); } - public static class ServerChannelInitializer extends AbstractChannelInitializer { + public static class ServerChannelInitializer extends AbstractChannelInitializer { + + public static final String DESERIALIZER_EX_HANDLER_KEY = "deserializerExHandler"; private final NetconfServerSessionNegotiatorFactory negotiatorFactory; private final NetconfServerSessionListenerFactory listenerFactory; @@ -51,11 +53,15 @@ public class NetconfServerDispatcher extends AbstractDispatcher promise) { - ch.pipeline().addLast("deserializerExHandler", new DeserializerExceptionHandler()); - ch.pipeline().addLast("negotiator", negotiatorFactory.getSessionNegotiator(listenerFactory, ch, promise)); + protected void initializeMessageDecoder(SocketChannel ch) { + super.initializeMessageDecoder(ch); + ch.pipeline().addLast(DESERIALIZER_EX_HANDLER_KEY, new DeserializerExceptionHandler()); } + @Override + protected void initializeSessionNegotiator(SocketChannel ch, Promise promise) { + ch.pipeline().addAfter(DESERIALIZER_EX_HANDLER_KEY, AbstractChannelInitializer.NETCONF_SESSION_NEGOTIATOR, negotiatorFactory.getSessionNegotiator(listenerFactory, ch, promise)); + } } } diff --git a/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/NetconfServerSession.java b/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/NetconfServerSession.java index 4cc05b7b42..9ddc64f1a1 100644 --- a/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/NetconfServerSession.java +++ b/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/NetconfServerSession.java @@ -15,9 +15,9 @@ import java.util.Date; import java.util.regex.Matcher; import java.util.regex.Pattern; -import org.opendaylight.controller.netconf.api.NetconfSession; +import org.opendaylight.controller.netconf.api.AbstractNetconfSession; import org.opendaylight.controller.netconf.api.monitoring.NetconfManagementSession; -import org.opendaylight.protocol.framework.SessionListener; +import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessageAdditionalHeader; 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; @@ -35,17 +35,17 @@ import org.slf4j.LoggerFactory; import com.google.common.base.Preconditions; -public class NetconfServerSession extends NetconfSession implements NetconfManagementSession { +public final class NetconfServerSession extends AbstractNetconfSession implements NetconfManagementSession { private static final Logger logger = LoggerFactory.getLogger(NetconfServerSession.class); - private final NetconfServerSessionNegotiator.AdditionalHeader header; + private final NetconfHelloMessageAdditionalHeader header; private Date loginTime; private long inRpcSuccess, inRpcFail, outRpcError; - public NetconfServerSession(SessionListener sessionListener, Channel channel, long sessionId, - NetconfServerSessionNegotiator.AdditionalHeader header) { + public NetconfServerSession(NetconfServerSessionListener sessionListener, Channel channel, long sessionId, + NetconfHelloMessageAdditionalHeader header) { super(sessionListener, channel, sessionId); this.header = header; logger.debug("Session {} created", toString()); @@ -72,6 +72,9 @@ public class NetconfServerSession extends NetconfSession implements NetconfManag public static final String ISO_DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX"; + private static final String dateTimePatternString = DateAndTime.PATTERN_CONSTANTS.get(0); + private static final Pattern dateTimePattern = Pattern.compile(dateTimePatternString); + @Override public Session toManagementSession() { SessionBuilder builder = new SessionBuilder(); @@ -81,16 +84,16 @@ public class NetconfServerSession extends NetconfSession implements NetconfManag Preconditions.checkState(DateAndTime.PATTERN_CONSTANTS.size() == 1); String formattedDateTime = formatDateTime(loginTime); - String pattern = DateAndTime.PATTERN_CONSTANTS.get(0); - Matcher matcher = Pattern.compile(pattern).matcher(formattedDateTime); - Preconditions.checkState(matcher.matches(), "Formatted datetime %s does not match pattern %s", formattedDateTime, pattern); + + Matcher matcher = dateTimePattern.matcher(formattedDateTime); + Preconditions.checkState(matcher.matches(), "Formatted datetime %s does not match pattern %s", formattedDateTime, dateTimePattern); builder.setLoginTime(new DateAndTime(formattedDateTime)); builder.setInBadRpcs(new ZeroBasedCounter32(inRpcFail)); builder.setInRpcs(new ZeroBasedCounter32(inRpcSuccess)); builder.setOutRpcErrors(new ZeroBasedCounter32(outRpcError)); - builder.setUsername(header.getUsername()); + builder.setUsername(header.getUserName()); builder.setTransport(getTransportForString(header.getTransport())); builder.setOutNotifications(new ZeroBasedCounter32(0L)); @@ -98,7 +101,7 @@ public class NetconfServerSession extends NetconfSession implements NetconfManag builder.setKey(new SessionKey(getSessionId())); Session1Builder builder1 = new Session1Builder(); - builder1.setSessionIdentifier(header.getSessionType()); + builder1.setSessionIdentifier(header.getSessionIdentifier()); builder.addAugmentation(Session1.class, builder1.build()); return builder.build(); @@ -106,9 +109,9 @@ public class NetconfServerSession extends NetconfSession implements NetconfManag private Class getTransportForString(String transport) { switch(transport) { - case "ssh" : return NetconfSsh.class; - case "tcp" : return NetconfTcp.class; - default: throw new IllegalArgumentException("Unknown transport type " + transport); + case "ssh" : return NetconfSsh.class; + case "tcp" : return NetconfTcp.class; + default: throw new IllegalArgumentException("Unknown transport type " + transport); } } @@ -117,4 +120,8 @@ public class NetconfServerSession extends NetconfSession implements NetconfManag return dateFormat.format(loginTime); } + @Override + protected NetconfServerSession thisInstance() { + return this; + } } diff --git a/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/NetconfServerSessionListener.java b/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/NetconfServerSessionListener.java index 43e55d746a..460288fe33 100644 --- a/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/NetconfServerSessionListener.java +++ b/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/NetconfServerSessionListener.java @@ -8,10 +8,11 @@ package org.opendaylight.controller.netconf.impl; -import com.google.common.base.Preconditions; -import com.google.common.collect.ImmutableMap; +import static com.google.common.base.Preconditions.checkState; + import org.opendaylight.controller.netconf.api.NetconfDocumentedException; import org.opendaylight.controller.netconf.api.NetconfMessage; +import org.opendaylight.controller.netconf.api.NetconfSessionListener; import org.opendaylight.controller.netconf.api.NetconfTerminationReason; import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationRouterImpl; import org.opendaylight.controller.netconf.impl.osgi.SessionMonitoringService; @@ -19,25 +20,22 @@ import org.opendaylight.controller.netconf.util.messages.SendErrorExceptionUtil; import org.opendaylight.controller.netconf.util.xml.XmlElement; import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants; import org.opendaylight.controller.netconf.util.xml.XmlUtil; -import org.opendaylight.protocol.framework.SessionListener; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Document; import org.w3c.dom.Node; -import static com.google.common.base.Preconditions.checkState; +import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableMap; -public class NetconfServerSessionListener implements - SessionListener { +public class NetconfServerSessionListener implements NetconfSessionListener { + public static final String MESSAGE_ID = "message-id"; static final Logger logger = LoggerFactory.getLogger(NetconfServerSessionListener.class); - public static final String MESSAGE_ID = "message-id"; private final SessionMonitoringService monitoringService; + private final NetconfOperationRouterImpl operationRouter; - private NetconfOperationRouterImpl operationRouter; - - public NetconfServerSessionListener(NetconfOperationRouterImpl operationRouter, - SessionMonitoringService monitoringService) { + public NetconfServerSessionListener(NetconfOperationRouterImpl operationRouter, SessionMonitoringService monitoringService) { this.operationRouter = operationRouter; this.monitoringService = monitoringService; } diff --git a/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/NetconfServerSessionNegotiator.java b/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/NetconfServerSessionNegotiator.java index 91555861dc..1b4dfff42b 100644 --- a/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/NetconfServerSessionNegotiator.java +++ b/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/NetconfServerSessionNegotiator.java @@ -8,86 +8,48 @@ package org.opendaylight.controller.netconf.impl; -import com.google.common.base.Optional; -import io.netty.channel.Channel; -import io.netty.util.Timer; -import io.netty.util.concurrent.Promise; -import org.opendaylight.controller.netconf.api.NetconfMessage; +import java.net.InetSocketAddress; + import org.opendaylight.controller.netconf.api.NetconfServerSessionPreferences; -import org.opendaylight.controller.netconf.impl.util.AdditionalHeaderUtil; import org.opendaylight.controller.netconf.util.AbstractNetconfSessionNegotiator; -import org.opendaylight.protocol.framework.SessionListener; +import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessage; +import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessageAdditionalHeader; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.net.InetSocketAddress; +import com.google.common.base.Optional; + +import io.netty.channel.Channel; +import io.netty.util.Timer; +import io.netty.util.concurrent.Promise; public class NetconfServerSessionNegotiator extends - AbstractNetconfSessionNegotiator { + AbstractNetconfSessionNegotiator { static final Logger logger = LoggerFactory.getLogger(NetconfServerSessionNegotiator.class); protected NetconfServerSessionNegotiator(NetconfServerSessionPreferences sessionPreferences, - Promise promise, Channel channel, Timer timer, SessionListener sessionListener, + Promise promise, Channel channel, Timer timer, NetconfServerSessionListener sessionListener, long connectionTimeoutMillis) { super(sessionPreferences, promise, channel, timer, sessionListener, connectionTimeoutMillis); } @Override - protected NetconfServerSession getSession(SessionListener sessionListener, Channel channel, NetconfMessage message) { - Optional additionalHeader = message.getAdditionalHeader(); + protected NetconfServerSession getSession(NetconfServerSessionListener sessionListener, Channel channel, NetconfHelloMessage message) { + Optional additionalHeader = message.getAdditionalHeader(); - AdditionalHeader parsedHeader; + NetconfHelloMessageAdditionalHeader parsedHeader; if (additionalHeader.isPresent()) { - parsedHeader = AdditionalHeaderUtil.fromString(additionalHeader.get()); + parsedHeader = additionalHeader.get(); } else { - parsedHeader = new AdditionalHeader("unknown", ((InetSocketAddress)channel.localAddress()).getHostString(), + InetSocketAddress inetSocketAddress = (InetSocketAddress) channel.localAddress(); + parsedHeader = new NetconfHelloMessageAdditionalHeader("unknown", inetSocketAddress.getHostString(), Integer.toString(inetSocketAddress.getPort()), "tcp", "client"); } + logger.debug("Additional header from hello parsed as {} from {}", parsedHeader, additionalHeader); return new NetconfServerSession(sessionListener, channel, sessionPreferences.getSessionId(), parsedHeader); } - public static class AdditionalHeader { - - private final String username; - private final String address; - private final String transport; - private final String sessionIdentifier; - - public AdditionalHeader(String userName, String hostAddress, String transport, String sessionIdentifier) { - this.address = hostAddress; - this.username = userName; - this.transport = transport; - this.sessionIdentifier = sessionIdentifier; - } - - String getUsername() { - return username; - } - - String getAddress() { - return address; - } - - String getTransport() { - return transport; - } - - String getSessionType() { - return sessionIdentifier; - } - - @Override - public String toString() { - final StringBuffer sb = new StringBuffer("AdditionalHeader{"); - sb.append("username='").append(username).append('\''); - sb.append(", address='").append(address).append('\''); - sb.append(", transport='").append(transport).append('\''); - sb.append('}'); - return sb.toString(); - } - } - -} + } diff --git a/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/NetconfServerSessionNegotiatorFactory.java b/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/NetconfServerSessionNegotiatorFactory.java index 98462b8025..e052f61cc9 100644 --- a/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/NetconfServerSessionNegotiatorFactory.java +++ b/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/NetconfServerSessionNegotiatorFactory.java @@ -12,11 +12,11 @@ import com.google.common.base.Preconditions; import io.netty.channel.Channel; import io.netty.util.Timer; import io.netty.util.concurrent.Promise; -import org.opendaylight.controller.netconf.api.NetconfMessage; import org.opendaylight.controller.netconf.api.NetconfServerSessionPreferences; import org.opendaylight.controller.netconf.impl.mapping.CapabilityProvider; import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceFactoryListener; import org.opendaylight.controller.netconf.util.NetconfUtil; +import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessage; import org.opendaylight.controller.netconf.util.xml.XMLNetconfUtil; import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants; import org.opendaylight.controller.netconf.util.xml.XmlUtil; @@ -31,7 +31,7 @@ import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathExpression; import java.io.InputStream; -public class NetconfServerSessionNegotiatorFactory implements SessionNegotiatorFactory { +public class NetconfServerSessionNegotiatorFactory implements SessionNegotiatorFactory { public static final String SERVER_HELLO_XML_LOCATION = "/server_hello.xml"; @@ -59,8 +59,8 @@ public class NetconfServerSessionNegotiatorFactory implements SessionNegotiatorF } @Override - public SessionNegotiator getSessionNegotiator(SessionListenerFactory sessionListenerFactory, Channel channel, - Promise promise) { + public SessionNegotiator getSessionNegotiator(SessionListenerFactory sessionListenerFactory, Channel channel, + Promise promise) { long sessionId = idProvider.getNextSessionId(); NetconfServerSessionPreferences proposal = new NetconfServerSessionPreferences(createHelloMessage(sessionId), @@ -74,7 +74,7 @@ public class NetconfServerSessionNegotiatorFactory implements SessionNegotiatorF private static final XPathExpression capabilitiesXPath = XMLNetconfUtil .compileXPath("/netconf:hello/netconf:capabilities"); - private NetconfMessage createHelloMessage(long sessionId) { + private NetconfHelloMessage createHelloMessage(long sessionId) { Document helloMessageTemplate = getHelloTemplateClone(); // change session ID @@ -93,10 +93,10 @@ public class NetconfServerSessionNegotiatorFactory implements SessionNegotiatorF capabilityElement.setTextContent(capability); capabilitiesElement.appendChild(capabilityElement); } - return new NetconfMessage(helloMessageTemplate); + return new NetconfHelloMessage(helloMessageTemplate); } private synchronized Document getHelloTemplateClone() { - return (Document) this.helloMessageTemplate.cloneNode(true); + return (Document) helloMessageTemplate.cloneNode(true); } } diff --git a/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/mapping/operations/DefaultCloseSession.java b/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/mapping/operations/DefaultCloseSession.java index cc503f60c3..1438515f04 100644 --- a/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/mapping/operations/DefaultCloseSession.java +++ b/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/mapping/operations/DefaultCloseSession.java @@ -8,10 +8,8 @@ package org.opendaylight.controller.netconf.impl.mapping.operations; -import org.opendaylight.controller.netconf.api.NetconfSession; import org.opendaylight.controller.netconf.api.NetconfDocumentedException; import org.opendaylight.controller.netconf.api.NetconfOperationRouter; -import org.opendaylight.controller.netconf.mapping.api.DefaultNetconfOperation; import org.opendaylight.controller.netconf.mapping.api.HandlingPriority; import org.opendaylight.controller.netconf.util.mapping.AbstractNetconfOperation; import org.opendaylight.controller.netconf.util.xml.XmlElement; @@ -19,9 +17,8 @@ import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants; import org.w3c.dom.Document; import org.w3c.dom.Element; -public class DefaultCloseSession extends AbstractNetconfOperation implements DefaultNetconfOperation { +public class DefaultCloseSession extends AbstractNetconfOperation { public static final String CLOSE_SESSION = "close-session"; - private NetconfSession netconfSession; public DefaultCloseSession(String netconfSessionIdForReporting) { super(netconfSessionIdForReporting); @@ -48,13 +45,4 @@ public class DefaultCloseSession extends AbstractNetconfOperation implements Def opRouter.close(); return document.createElement(XmlNetconfConstants.OK); } - - @Override - public void setNetconfSession(NetconfSession s) { - this.netconfSession = s; - } - - public NetconfSession getNetconfSession() { - return netconfSession; - } } diff --git a/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/mapping/operations/DefaultGetSchema.java b/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/mapping/operations/DefaultGetSchema.java index f34529d53f..904f3f613e 100644 --- a/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/mapping/operations/DefaultGetSchema.java +++ b/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/mapping/operations/DefaultGetSchema.java @@ -11,11 +11,9 @@ package org.opendaylight.controller.netconf.impl.mapping.operations; import java.util.HashMap; import java.util.Map; -import org.opendaylight.controller.netconf.api.NetconfSession; import org.opendaylight.controller.netconf.api.NetconfDocumentedException; import org.opendaylight.controller.netconf.api.NetconfOperationRouter; import org.opendaylight.controller.netconf.impl.mapping.CapabilityProvider; -import org.opendaylight.controller.netconf.mapping.api.DefaultNetconfOperation; import org.opendaylight.controller.netconf.mapping.api.HandlingPriority; import org.opendaylight.controller.netconf.util.mapping.AbstractNetconfOperation; import org.opendaylight.controller.netconf.util.xml.XmlElement; @@ -29,22 +27,19 @@ import org.w3c.dom.Element; import com.google.common.base.Optional; import com.google.common.collect.Maps; -public final class DefaultGetSchema extends AbstractNetconfOperation implements DefaultNetconfOperation { - - private final CapabilityProvider cap; - private NetconfSession netconfSession; +public final class DefaultGetSchema extends AbstractNetconfOperation { + public static final String GET_SCHEMA = "get-schema"; + public static final String IDENTIFIER = "identifier"; + public static final String VERSION = "version"; private static final Logger logger = LoggerFactory.getLogger(DefaultGetSchema.class); + private final CapabilityProvider cap; public DefaultGetSchema(CapabilityProvider cap, String netconfSessionIdForReporting) { super(netconfSessionIdForReporting); this.cap = cap; } - public static final String GET_SCHEMA = "get-schema"; - public static final String IDENTIFIER = "identifier"; - public static final String VERSION = "version"; - @Override protected HandlingPriority canHandle(String netconfOperationName, String namespace) { if (netconfOperationName.equals("get-schema") == false) @@ -117,15 +112,6 @@ public final class DefaultGetSchema extends AbstractNetconfOperation implements } else { version = Optional.absent(); } - } } - - public void setNetconfSession(NetconfSession s) { - this.netconfSession = s; - } - - public NetconfSession getNetconfSession() { - return netconfSession; - } } diff --git a/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/osgi/NetconfOperationRouterImpl.java b/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/osgi/NetconfOperationRouterImpl.java index d70a15c18b..ece9d47ee9 100644 --- a/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/osgi/NetconfOperationRouterImpl.java +++ b/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/osgi/NetconfOperationRouterImpl.java @@ -7,12 +7,18 @@ */ package org.opendaylight.controller.netconf.impl.osgi; -import com.google.common.base.Preconditions; -import com.google.common.collect.Maps; -import com.google.common.collect.Sets; -import org.opendaylight.controller.netconf.api.NetconfSession; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; +import java.util.TreeSet; + import org.opendaylight.controller.netconf.api.NetconfDocumentedException; import org.opendaylight.controller.netconf.api.NetconfOperationRouter; +import org.opendaylight.controller.netconf.api.NetconfSession; import org.opendaylight.controller.netconf.impl.DefaultCommitNotificationProducer; import org.opendaylight.controller.netconf.impl.mapping.CapabilityProvider; import org.opendaylight.controller.netconf.impl.mapping.operations.DefaultCloseSession; @@ -31,14 +37,9 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Document; -import java.util.Collections; -import java.util.HashSet; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.Map; -import java.util.Set; -import java.util.TreeMap; -import java.util.TreeSet; +import com.google.common.base.Preconditions; +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; public class NetconfOperationRouterImpl implements NetconfOperationRouter { @@ -55,24 +56,19 @@ public class NetconfOperationRouterImpl implements NetconfOperationRouter { public NetconfOperationRouterImpl(NetconfOperationServiceSnapshot netconfOperationServiceSnapshot, CapabilityProvider capabilityProvider, DefaultCommitNotificationProducer commitNotifier) { - this.netconfOperationServiceSnapshot = netconfOperationServiceSnapshot; + this.netconfOperationServiceSnapshot = Preconditions.checkNotNull(netconfOperationServiceSnapshot); + this.capabilityProvider = Preconditions.checkNotNull(capabilityProvider); - this.capabilityProvider = capabilityProvider; - - Set defaultNetconfOperations = Sets.newHashSet(); - defaultNetconfOperations.add(new DefaultGetSchema(capabilityProvider, netconfOperationServiceSnapshot - .getNetconfSessionIdForReporting())); - defaultNetconfOperations.add(new DefaultCloseSession(netconfOperationServiceSnapshot - .getNetconfSessionIdForReporting())); - defaultNetconfOperations.add(new DefaultStartExi(netconfOperationServiceSnapshot - .getNetconfSessionIdForReporting())); - defaultNetconfOperations.add(new DefaultStopExi(netconfOperationServiceSnapshot - .getNetconfSessionIdForReporting())); + final String sessionId = netconfOperationServiceSnapshot.getNetconfSessionIdForReporting(); + final Set defaultNetconfOperations = Sets.newHashSet(); + defaultNetconfOperations.add(new DefaultGetSchema(capabilityProvider, sessionId)); + defaultNetconfOperations.add(new DefaultCloseSession(sessionId)); + defaultNetconfOperations.add(new DefaultStartExi(sessionId)); + defaultNetconfOperations.add(new DefaultStopExi(sessionId)); allNetconfOperations = getAllNetconfOperations(defaultNetconfOperations, netconfOperationServiceSnapshot); - DefaultCommit defaultCommit = new DefaultCommit(commitNotifier, capabilityProvider, - netconfOperationServiceSnapshot.getNetconfSessionIdForReporting()); + DefaultCommit defaultCommit = new DefaultCommit(commitNotifier, capabilityProvider, sessionId); Set defaultFilters = Sets. newHashSet(defaultCommit); allSortedFilters = getAllNetconfFilters(defaultFilters, netconfOperationServiceSnapshot); } @@ -238,10 +234,6 @@ public class NetconfOperationRouterImpl implements NetconfOperationRouter { private class NetconfOperationExecution implements NetconfOperationFilterChain { private final NetconfOperation operationWithHighestPriority; - private NetconfOperationExecution(NetconfOperation operationWithHighestPriority) { - this.operationWithHighestPriority = operationWithHighestPriority; - } - public NetconfOperationExecution(TreeMap> sortedPriority, HandlingPriority highestFoundPriority) { operationWithHighestPriority = sortedPriority.get(highestFoundPriority).iterator().next(); diff --git a/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/util/AdditionalHeaderUtil.java b/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/util/AdditionalHeaderUtil.java deleted file mode 100644 index 5c630dd343..0000000000 --- a/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/util/AdditionalHeaderUtil.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v1.0 which accompanies this distribution, - * and is available at http://www.eclipse.org/legal/epl-v10.html - */ - -package org.opendaylight.controller.netconf.impl.util; - -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.opendaylight.controller.netconf.impl.NetconfServerSessionNegotiator.AdditionalHeader; - -import com.google.common.base.Preconditions; - -public class AdditionalHeaderUtil { - - private static final Pattern pattern = Pattern - .compile("\\[(?[^;]+);(?
[0-9\\.]+)[:/](?[0-9]+);(?[a-z]+)[^\\]]+\\]"); - private static final Pattern customHeaderPattern = Pattern - .compile("\\[(?[^;]+);(?
[0-9\\.]+)[:/](?[0-9]+);(?[a-z]+);(?[a-z]+)[^\\]]+\\]"); - - public static AdditionalHeader fromString(String additionalHeader) { - additionalHeader = additionalHeader.trim(); - Matcher matcher = pattern.matcher(additionalHeader); - Matcher matcher2 = customHeaderPattern.matcher(additionalHeader); - Preconditions.checkArgument(matcher.matches(), "Additional header in wrong format %s, expected %s", - additionalHeader, pattern); - String username = matcher.group("username"); - String address = matcher.group("address"); - String transport = matcher.group("transport"); - String sessionIdentifier = "client"; - if (matcher2.matches()) { - sessionIdentifier = matcher2.group("sessionIdentifier"); - } - return new AdditionalHeader(username, address, transport, sessionIdentifier); - } - -} diff --git a/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/AdditionalHeaderParserTest.java b/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/AdditionalHeaderParserTest.java index 97d9a98b57..c2dcd67921 100644 --- a/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/AdditionalHeaderParserTest.java +++ b/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/AdditionalHeaderParserTest.java @@ -10,15 +10,15 @@ package org.opendaylight.controller.netconf.impl; import junit.framework.Assert; import org.junit.Test; -import org.opendaylight.controller.netconf.impl.util.AdditionalHeaderUtil; +import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessageAdditionalHeader; public class AdditionalHeaderParserTest { @Test public void testParsing() throws Exception { String s = "[netconf;10.12.0.102:48528;ssh;;;;;;]"; - NetconfServerSessionNegotiator.AdditionalHeader header = AdditionalHeaderUtil.fromString(s); - Assert.assertEquals("netconf", header.getUsername()); + NetconfHelloMessageAdditionalHeader header = NetconfHelloMessageAdditionalHeader.fromString(s); + Assert.assertEquals("netconf", header.getUserName()); Assert.assertEquals("10.12.0.102", header.getAddress()); Assert.assertEquals("ssh", header.getTransport()); } @@ -26,8 +26,8 @@ public class AdditionalHeaderParserTest { @Test public void testParsing2() throws Exception { String s = "[tomas;10.0.0.0/10000;tcp;1000;1000;;/home/tomas;;]"; - NetconfServerSessionNegotiator.AdditionalHeader header = AdditionalHeaderUtil.fromString(s); - Assert.assertEquals("tomas", header.getUsername()); + NetconfHelloMessageAdditionalHeader header = NetconfHelloMessageAdditionalHeader.fromString(s); + Assert.assertEquals("tomas", header.getUserName()); Assert.assertEquals("10.0.0.0", header.getAddress()); Assert.assertEquals("tcp", header.getTransport()); } @@ -35,6 +35,6 @@ public class AdditionalHeaderParserTest { @Test(expected = IllegalArgumentException.class) public void testParsingNoUsername() throws Exception { String s = "[10.12.0.102:48528;ssh;;;;;;]"; - AdditionalHeaderUtil.fromString(s); + NetconfHelloMessageAdditionalHeader.fromString(s); } } diff --git a/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/ConcurrentClientsTest.java b/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/ConcurrentClientsTest.java index 0ef2c285e4..c0d52ad85e 100644 --- a/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/ConcurrentClientsTest.java +++ b/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/ConcurrentClientsTest.java @@ -37,6 +37,7 @@ import org.opendaylight.controller.netconf.mapping.api.NetconfOperation; import org.opendaylight.controller.netconf.mapping.api.NetconfOperationFilter; import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService; import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactory; +import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessageAdditionalHeader; import org.opendaylight.controller.netconf.util.test.XmlFileLoader; import org.opendaylight.controller.netconf.util.xml.XmlUtil; import org.slf4j.Logger; @@ -100,7 +101,8 @@ public class ConcurrentClientsTest { } nettyGroup = new NioEventLoopGroup(); - netconfClientDispatcher = new NetconfClientDispatcher( nettyGroup, nettyGroup, 5000); + NetconfHelloMessageAdditionalHeader additionalHeader = new NetconfHelloMessageAdditionalHeader("uname", "10.10.10.1", "830", "tcp", "client"); + netconfClientDispatcher = new NetconfClientDispatcher( nettyGroup, nettyGroup, additionalHeader, 5000); NetconfOperationServiceFactoryListenerImpl factoriesListener = new NetconfOperationServiceFactoryListenerImpl(); factoriesListener.onAddNetconfOperationServiceFactory(mockOpF()); diff --git a/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/MessageParserTest.java b/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/MessageParserTest.java index baf2d7d761..85bccba14f 100644 --- a/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/MessageParserTest.java +++ b/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/MessageParserTest.java @@ -13,30 +13,28 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; - -import java.util.Queue; - import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; import io.netty.channel.embedded.EmbeddedChannel; +import java.util.Queue; + import org.junit.Before; import org.junit.Test; import org.opendaylight.controller.netconf.api.NetconfMessage; 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.NetconfMessageToXMLEncoder; +import org.opendaylight.controller.netconf.util.handler.NetconfXMLToMessageDecoder; import org.opendaylight.controller.netconf.util.messages.FramingMechanism; import org.opendaylight.controller.netconf.util.messages.NetconfMessageConstants; -import org.opendaylight.controller.netconf.util.messages.NetconfMessageFactory; import org.opendaylight.controller.netconf.util.messages.NetconfMessageHeader; import org.opendaylight.controller.netconf.util.test.XmlFileLoader; -import org.opendaylight.protocol.framework.ProtocolMessageDecoder; -import org.opendaylight.protocol.framework.ProtocolMessageEncoder; public class MessageParserTest { private NetconfMessage msg; - private NetconfMessageFactory msgFactory = new NetconfMessageFactory(); @Before public void setUp() throws Exception { @@ -47,16 +45,20 @@ public class MessageParserTest { public void testChunkedFramingMechanismOnPipeline() throws Exception { EmbeddedChannel testChunkChannel = new EmbeddedChannel( FramingMechanismHandlerFactory.createHandler(FramingMechanism.CHUNK), - new ProtocolMessageEncoder(msgFactory), + new NetconfMessageToXMLEncoder(), new NetconfMessageAggregator(FramingMechanism.CHUNK), new NetconfMessageChunkDecoder(), - new ProtocolMessageDecoder(msgFactory)); + new NetconfXMLToMessageDecoder()); testChunkChannel.writeOutbound(this.msg); Queue messages = testChunkChannel.outboundMessages(); assertFalse(messages.isEmpty()); - int msgLength = this.msgFactory.put(this.msg).length; + final NetconfMessageToXMLEncoder enc = new NetconfMessageToXMLEncoder(); + final ByteBuf out = Unpooled.buffer(); + enc.encode(null, msg, out); + int msgLength = out.readableBytes(); + int chunkCount = msgLength / NetconfMessageConstants.MAX_CHUNK_SIZE; if ((msgLength % NetconfMessageConstants.MAX_CHUNK_SIZE) != 0) { chunkCount++; @@ -92,8 +94,8 @@ public class MessageParserTest { public void testEOMFramingMechanismOnPipeline() throws Exception { EmbeddedChannel testChunkChannel = new EmbeddedChannel( FramingMechanismHandlerFactory.createHandler(FramingMechanism.EOM), - new ProtocolMessageEncoder(msgFactory), new NetconfMessageAggregator( - FramingMechanism.EOM), new ProtocolMessageDecoder(msgFactory)); + new NetconfMessageToXMLEncoder(), new NetconfMessageAggregator( + FramingMechanism.EOM), new NetconfXMLToMessageDecoder()); testChunkChannel.writeOutbound(this.msg); ByteBuf recievedOutbound = (ByteBuf) testChunkChannel.readOutbound(); diff --git a/opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/NetconfITTest.java b/opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/NetconfITTest.java index 954da5f487..fce3f70e73 100644 --- a/opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/NetconfITTest.java +++ b/opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/NetconfITTest.java @@ -8,12 +8,33 @@ package org.opendaylight.controller.netconf.it; -import ch.ethz.ssh2.Connection; -import ch.ethz.ssh2.Session; -import com.google.common.collect.Lists; -import com.google.common.collect.Sets; +import static java.util.Collections.emptyList; +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertNotNull; +import static junit.framework.Assert.assertTrue; +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.IOException; +import java.io.InputStream; +import java.lang.management.ManagementFactory; +import java.net.InetSocketAddress; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Set; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeoutException; + +import javax.management.ObjectName; +import javax.xml.parsers.ParserConfigurationException; + import junit.framework.Assert; + import org.junit.After; import org.junit.Before; import org.junit.Ignore; @@ -52,26 +73,11 @@ import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.xml.sax.SAXException; -import javax.management.ObjectName; -import javax.xml.parsers.ParserConfigurationException; -import java.io.IOException; -import java.io.InputStream; -import java.lang.management.ManagementFactory; -import java.net.InetSocketAddress; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Set; +import ch.ethz.ssh2.Connection; +import ch.ethz.ssh2.Session; -import static java.util.Collections.emptyList; -import static junit.framework.Assert.assertEquals; -import static junit.framework.Assert.assertNotNull; -import static junit.framework.Assert.assertTrue; -import static org.mockito.Matchers.anyLong; -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 NetconfITTest extends AbstractNetconfConfigTest { @@ -85,7 +91,7 @@ public class NetconfITTest extends AbstractNetconfConfigTest { private static final String PASSWORD = "netconf"; private NetconfMessage getConfig, getConfigCandidate, editConfig, - closeSession, startExi, stopExi; + closeSession, startExi, stopExi; private DefaultCommitNotificationProducer commitNot; private NetconfServerDispatcher dispatch; @@ -304,7 +310,7 @@ public class NetconfITTest extends AbstractNetconfConfigTest { } } - */ + */ @Test public void testCloseSession() throws Exception { @@ -350,12 +356,12 @@ public class NetconfITTest extends AbstractNetconfConfigTest { assertEquals("ok", XmlElement.fromDomDocument(rpcReply).getOnlyChildElement().getName()); } - private Document assertGetConfigWorks(final NetconfClient netconfClient) throws InterruptedException { + private Document assertGetConfigWorks(final NetconfClient netconfClient) throws InterruptedException, ExecutionException, TimeoutException { return assertGetConfigWorks(netconfClient, this.getConfig); } private Document assertGetConfigWorks(final NetconfClient netconfClient, final NetconfMessage getConfigMessage) - throws InterruptedException { + throws InterruptedException, ExecutionException, TimeoutException { final NetconfMessage rpcReply = netconfClient.sendMessage(getConfigMessage); assertNotNull(rpcReply); assertEquals("data", XmlElement.fromDomDocument(rpcReply.getDocument()).getOnlyChildElement().getName()); @@ -423,19 +429,20 @@ public class NetconfITTest extends AbstractNetconfConfigTest { sess.getStdin().write(XmlUtil.toString(this.getConfig.getDocument()).getBytes()); new Thread(){ - public void run(){ - while (true){ - byte[] bytes = new byte[1024]; - int c = 0; - try { - c = sess.getStdout().read(bytes); - } catch (IOException e) { - e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. - } - logger.info("got data:"+bytes); - if (c == 0) break; - } - } + @Override + public void run(){ + while (true){ + byte[] bytes = new byte[1024]; + int c = 0; + try { + c = sess.getStdout().read(bytes); + } catch (IOException e) { + e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. + } + logger.info("got data:"+bytes); + if (c == 0) break; + } + } }.join(); } diff --git a/opendaylight/netconf/netconf-monitoring/src/main/java/org/opendaylight/controller/netconf/monitoring/MonitoringConstants.java b/opendaylight/netconf/netconf-monitoring/src/main/java/org/opendaylight/controller/netconf/monitoring/MonitoringConstants.java index 3a9d3bacc2..200cd344a6 100644 --- a/opendaylight/netconf/netconf-monitoring/src/main/java/org/opendaylight/controller/netconf/monitoring/MonitoringConstants.java +++ b/opendaylight/netconf/netconf-monitoring/src/main/java/org/opendaylight/controller/netconf/monitoring/MonitoringConstants.java @@ -9,10 +9,14 @@ package org.opendaylight.controller.netconf.monitoring; 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"; diff --git a/opendaylight/netconf/netconf-monitoring/src/main/java/org/opendaylight/controller/netconf/monitoring/xml/model/MonitoringSession.java b/opendaylight/netconf/netconf-monitoring/src/main/java/org/opendaylight/controller/netconf/monitoring/xml/model/MonitoringSession.java index 55aee72fda..8685ef7220 100644 --- a/opendaylight/netconf/netconf-monitoring/src/main/java/org/opendaylight/controller/netconf/monitoring/xml/model/MonitoringSession.java +++ b/opendaylight/netconf/netconf-monitoring/src/main/java/org/opendaylight/controller/netconf/monitoring/xml/model/MonitoringSession.java @@ -10,6 +10,8 @@ package org.opendaylight.controller.netconf.monitoring.xml.model; 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; @@ -69,13 +71,18 @@ final class MonitoringSession { 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(); } diff --git a/opendaylight/netconf/netconf-monitoring/src/main/java/org/opendaylight/controller/netconf/monitoring/xml/model/package-info.java b/opendaylight/netconf/netconf-monitoring/src/main/java/org/opendaylight/controller/netconf/monitoring/xml/model/package-info.java index 85da5975d1..a96c3a3836 100644 --- a/opendaylight/netconf/netconf-monitoring/src/main/java/org/opendaylight/controller/netconf/monitoring/xml/model/package-info.java +++ b/opendaylight/netconf/netconf-monitoring/src/main/java/org/opendaylight/controller/netconf/monitoring/xml/model/package-info.java @@ -7,14 +7,16 @@ */ @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 diff --git a/opendaylight/netconf/netconf-monitoring/src/test/java/org/opendaylight/controller/netconf/monitoring/xml/JaxBSerializerTest.java b/opendaylight/netconf/netconf-monitoring/src/test/java/org/opendaylight/controller/netconf/monitoring/xml/JaxBSerializerTest.java index d4462f85d9..02129574da 100644 --- a/opendaylight/netconf/netconf-monitoring/src/test/java/org/opendaylight/controller/netconf/monitoring/xml/JaxBSerializerTest.java +++ b/opendaylight/netconf/netconf-monitoring/src/test/java/org/opendaylight/controller/netconf/monitoring/xml/JaxBSerializerTest.java @@ -13,8 +13,10 @@ import org.opendaylight.controller.netconf.api.monitoring.NetconfMonitoringServi 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; @@ -39,7 +41,7 @@ public class JaxBSerializerTest { @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 @@ -51,7 +53,7 @@ public class JaxBSerializerTest { Element xml = new JaxBSerializer().toXml(model); } - private Session getMockSession() { + private Session getMockSession(Class transportType) { Session mocked = mock(Session.class); Session1 mockedSession1 = mock(Session1.class); doReturn("client").when(mockedSession1).getSessionIdentifier(); @@ -62,7 +64,7 @@ public class JaxBSerializerTest { 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; diff --git a/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/authentication/AuthProvider.java b/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/authentication/AuthProvider.java index d904ad7f26..3d5318073d 100644 --- a/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/authentication/AuthProvider.java +++ b/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/authentication/AuthProvider.java @@ -30,14 +30,14 @@ public class AuthProvider implements AuthProviderInterface { 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 roles = new ArrayList(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); @@ -48,10 +48,10 @@ public class AuthProvider implements AuthProviderInterface { } @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; } @@ -69,12 +69,12 @@ public class AuthProvider implements AuthProviderInterface { @Override public void removeUserManagerService() { - this.um = null; + AuthProvider.um = null; } @Override public void addUserManagerService(IUserManager userManagerService) { - this.um = userManagerService; + AuthProvider.um = userManagerService; } diff --git a/opendaylight/netconf/netconf-ssh/src/test/java/org/opendaylight/controller/netconf/StubUserManager.java b/opendaylight/netconf/netconf-ssh/src/test/java/org/opendaylight/controller/netconf/StubUserManager.java index 4a3a650ecd..6628310c97 100644 --- a/opendaylight/netconf/netconf-ssh/src/test/java/org/opendaylight/controller/netconf/StubUserManager.java +++ b/opendaylight/netconf/netconf-ssh/src/test/java/org/opendaylight/controller/netconf/StubUserManager.java @@ -30,8 +30,8 @@ public class StubUserManager implements IUserManager{ 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 getUserRoles(String userName) { @@ -40,7 +40,7 @@ public class StubUserManager implements IUserManager{ @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; diff --git a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/AbstractChannelInitializer.java b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/AbstractChannelInitializer.java index aeee2fb04b..0910d9403a 100644 --- a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/AbstractChannelInitializer.java +++ b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/AbstractChannelInitializer.java @@ -10,24 +10,47 @@ package org.opendaylight.controller.netconf.util; import io.netty.channel.socket.SocketChannel; import io.netty.util.concurrent.Promise; + import org.opendaylight.controller.netconf.api.NetconfSession; import org.opendaylight.controller.netconf.util.handler.FramingMechanismHandlerFactory; -import org.opendaylight.controller.netconf.util.handler.NetconfHandlerFactory; +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; -import org.opendaylight.controller.netconf.util.messages.NetconfMessageFactory; -public abstract class AbstractChannelInitializer { +public abstract class AbstractChannelInitializer { + + public static final String NETCONF_MESSAGE_DECODER = "netconfMessageDecoder"; + public static final String NETCONF_MESSAGE_AGGREGATOR = "aggregator"; + public static final String NETCONF_MESSAGE_ENCODER = "netconfMessageEncoder"; + public static final String NETCONF_MESSAGE_FRAME_ENCODER = "frameEncoder"; + public static final String NETCONF_SESSION_NEGOTIATOR = "negotiator"; + + public void initialize(SocketChannel ch, Promise promise) { + ch.pipeline().addLast(NETCONF_MESSAGE_AGGREGATOR, new NetconfMessageAggregator(FramingMechanism.EOM)); + initializeMessageDecoder(ch); + ch.pipeline().addLast(NETCONF_MESSAGE_FRAME_ENCODER, FramingMechanismHandlerFactory.createHandler(FramingMechanism.EOM)); + initializeMessageEncoder(ch); + + initializeSessionNegotiator(ch, promise); + } + + protected void initializeMessageEncoder(SocketChannel ch) { + // Special encoding handler for hello message to include additional header if available, + // it is thrown away after successful negotiation + ch.pipeline().addLast(NETCONF_MESSAGE_ENCODER, new NetconfHelloMessageToXMLEncoder()); + } - public void initialize(SocketChannel ch, Promise promise){ - NetconfHandlerFactory handlerFactory = new NetconfHandlerFactory(new NetconfMessageFactory()); - ch.pipeline().addLast("aggregator", new NetconfMessageAggregator(FramingMechanism.EOM)); - ch.pipeline().addLast(handlerFactory.getDecoders()); - initializeAfterDecoder(ch, promise); - ch.pipeline().addLast("frameEncoder", FramingMechanismHandlerFactory.createHandler(FramingMechanism.EOM)); - ch.pipeline().addLast(handlerFactory.getEncoders()); + protected void initializeMessageDecoder(SocketChannel ch) { + // Special decoding handler for hello message to parse additional header if available, + // it is thrown away after successful negotiation + ch.pipeline().addLast(NETCONF_MESSAGE_DECODER, new NetconfXMLToHelloMessageDecoder()); } - protected abstract void initializeAfterDecoder(SocketChannel ch, Promise promise); + /** + * Insert session negotiator into the pipeline. It must be inserted after message decoder + * identified by {@link AbstractChannelInitializer#NETCONF_MESSAGE_DECODER}, (or any other custom decoder processor) + */ + protected abstract void initializeSessionNegotiator(SocketChannel ch, Promise promise); } diff --git a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/AbstractNetconfSessionNegotiator.java b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/AbstractNetconfSessionNegotiator.java index 8cfd177fce..9986b82bd8 100644 --- a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/AbstractNetconfSessionNegotiator.java +++ b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/AbstractNetconfSessionNegotiator.java @@ -8,46 +8,50 @@ package org.opendaylight.controller.netconf.util; -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; +import java.util.concurrent.TimeUnit; + +import org.opendaylight.controller.netconf.api.AbstractNetconfSession; import org.opendaylight.controller.netconf.api.NetconfMessage; -import org.opendaylight.controller.netconf.api.NetconfSession; +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.NetconfMessageToXMLEncoder; +import org.opendaylight.controller.netconf.util.handler.NetconfXMLToMessageDecoder; import org.opendaylight.controller.netconf.util.messages.FramingMechanism; -import org.opendaylight.controller.netconf.util.xml.XmlElement; -import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants; import org.opendaylight.controller.netconf.util.xml.XmlUtil; import org.opendaylight.protocol.framework.AbstractSessionNegotiator; -import org.opendaylight.protocol.framework.SessionListener; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Document; import org.w3c.dom.NodeList; -import java.util.concurrent.TimeUnit; +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

- extends AbstractSessionNegotiator { +public abstract class AbstractNetconfSessionNegotiator

, L extends NetconfSessionListener> +extends AbstractSessionNegotiator { 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 SessionListener sessionListener; + private final L sessionListener; private Timeout timeout; /** @@ -62,7 +66,7 @@ public abstract class AbstractNetconfSessionNegotiator

promise, Channel channel, Timer timer, - SessionListener sessionListener, long connectionTimeoutMillis) { + L sessionListener, long connectionTimeoutMillis) { super(promise, channel); this.sessionPreferences = sessionPreferences; this.timer = timer; @@ -119,7 +123,7 @@ public abstract class AbstractNetconfSessionNegotiator

{ - - public NetconfHandlerFactory(final NetconfMessageFactory msgFactory) { - super(msgFactory); - } - - @Override - public ChannelHandler[] getEncoders() { - return new ChannelHandler[] { new ProtocolMessageEncoder(this.msgFactory) }; - } - - @Override - public ChannelHandler[] getDecoders() { - return new ChannelHandler[] { new ProtocolMessageDecoder(this.msgFactory) }; - } - -} diff --git a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/handler/NetconfHelloMessageToXMLEncoder.java b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/handler/NetconfHelloMessageToXMLEncoder.java new file mode 100644 index 0000000000..a87d175d78 --- /dev/null +++ b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/handler/NetconfHelloMessageToXMLEncoder.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.controller.netconf.util.handler; + +import java.nio.ByteBuffer; + +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.base.Charsets; +import com.google.common.base.Optional; +import com.google.common.base.Preconditions; + +/** + * Customized NetconfMessageToXMLEncoder that serializes additional header with + * session metadata along with + * {@link org.opendaylight.controller.netconf.util.messages.NetconfHelloMessage} + * . Used by netconf clients to send information about the user, ip address, + * protocol etc. + *

+ * Hello message with header example: + *

+ * + *

+ * {@code
+ * [tomas;10.0.0.0/10000;tcp;1000;1000;;/home/tomas;;]
+ * 
+ * 
+ * urn:ietf:params:netconf:base:1.0
+ * 
+ * 
+ * }
+ * 
+ */ +public final class NetconfHelloMessageToXMLEncoder extends NetconfMessageToXMLEncoder { + + @Override + protected ByteBuffer encodeMessage(NetconfMessage msg) { + Preconditions.checkState(msg instanceof NetconfHelloMessage, "Netconf message of type %s expected, was %s", + NetconfHelloMessage.class, msg.getClass()); + Optional headerOptional = ((NetconfHelloMessage) msg) + .getAdditionalHeader(); + + // 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; + } + + return super.encodeMessage(msg); + } +} diff --git a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/handler/NetconfMessageChunkDecoder.java b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/handler/NetconfMessageChunkDecoder.java index 39182263b6..5c00b9b715 100644 --- a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/handler/NetconfMessageChunkDecoder.java +++ b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/handler/NetconfMessageChunkDecoder.java @@ -8,19 +8,19 @@ 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.opendaylight.protocol.framework.DeserializerException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.channel.ChannelHandlerContext; -import io.netty.handler.codec.ByteToMessageDecoder; - public class NetconfMessageChunkDecoder extends ByteToMessageDecoder { private final static Logger logger = LoggerFactory.getLogger(NetconfMessageChunkDecoder.class); @@ -40,7 +40,7 @@ public class NetconfMessageChunkDecoder extends ByteToMessageDecoder { in.readBytes(byteBufMsg, chunkSize); isParsed = false; } else { - throw new DeserializerException("Unable to parse chunked data or header."); + throw new NetconfDeserializerException("Unable to parse chunked data or header."); } } catch (Exception e) { logger.error("Failed to decode chunked message.", e); diff --git a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/handler/NetconfMessageToXMLEncoder.java b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/handler/NetconfMessageToXMLEncoder.java new file mode 100644 index 0000000000..df0f7ef46a --- /dev/null +++ b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/handler/NetconfMessageToXMLEncoder.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.controller.netconf.util.handler; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.MessageToByteEncoder; + +import java.nio.ByteBuffer; + +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 { + private static final Logger LOG = LoggerFactory.getLogger(NetconfMessageToXMLEncoder.class); + + private final Optional clientId; + + public NetconfMessageToXMLEncoder() { + this(Optional.absent()); + } + + public NetconfMessageToXMLEncoder(Optional clientId) { + this.clientId = clientId; + } + + @Override + @VisibleForTesting + public void encode(ChannelHandlerContext ctx, NetconfMessage msg, ByteBuf out) throws Exception { + LOG.debug("Sent to encode : {}", msg); + + if (clientId.isPresent()) { + Comment comment = msg.getDocument().createComment("clientId:" + clientId.get()); + 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())); + } + + protected String xmlToString(Document doc) { + return XmlUtil.toString(doc, false); + } +} diff --git a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/handler/NetconfXMLToHelloMessageDecoder.java b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/handler/NetconfXMLToHelloMessageDecoder.java new file mode 100644 index 0000000000..42586a5ecc --- /dev/null +++ b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/handler/NetconfXMLToHelloMessageDecoder.java @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.controller.netconf.util.handler; + +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.w3c.dom.Document; + +import com.google.common.base.Charsets; +import com.google.common.collect.ImmutableList; + +/** + * Customized NetconfXMLToMessageDecoder that reads additional header with + * session metadata from + * {@link org.opendaylight.controller.netconf.util.messages.NetconfHelloMessage} + * . Used by netconf server to retrieve information about session metadata. + */ +public class NetconfXMLToHelloMessageDecoder extends NetconfXMLToMessageDecoder { + + private static final List POSSIBLE_ENDS = ImmutableList.of( + new byte[] { ']', '\n' }, + new byte[] { ']', '\r', '\n' }); + private static final List POSSIBLE_STARTS = ImmutableList.of( + new byte[] { '[' }, + 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); + } + } + + return bytes; + } + + @Override + protected void cleanUpAfterDecode() { + additionalHeaderCache = null; + } + + @Override + protected NetconfMessage buildNetconfMessage(Document doc) { + return new NetconfHelloMessage(doc, additionalHeaderCache == null ? null + : NetconfHelloMessageAdditionalHeader.fromString(additionalHeaderCache)); + } + + private int getAdditionalHeaderEndIndex(byte[] bytes) { + for (byte[] possibleEnd : POSSIBLE_ENDS) { + int idx = findByteSequence(bytes, possibleEnd); + + if (idx != -1) { + return idx; + } + } + + return -1; + } + + private static int findByteSequence(final byte[] bytes, final byte[] sequence) { + if (bytes.length < sequence.length) { + throw new IllegalArgumentException("Sequence to be found is longer than the given byte array."); + } + if (bytes.length == sequence.length) { + if (Arrays.equals(bytes, sequence)) { + return 0; + } else { + return -1; + } + } + int j = 0; + for (int i = 0; i < bytes.length; i++) { + if (bytes[i] == sequence[j]) { + j++; + if (j == sequence.length) { + return i - j + 1; + } + } else { + j = 0; + } + } + return -1; + } + + private boolean startsWithAdditionalHeader(byte[] bytes) { + for (byte[] possibleStart : POSSIBLE_STARTS) { + int i = 0; + for (byte b : possibleStart) { + if(bytes[i++] != b) + break; + + if(i == possibleStart.length) + return true; + } + } + + return false; + } + + private String additionalHeaderToString(byte[] bytes) { + return Charsets.UTF_8.decode(ByteBuffer.wrap(bytes)).toString(); + } + +} diff --git a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/handler/NetconfXMLToMessageDecoder.java b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/handler/NetconfXMLToMessageDecoder.java new file mode 100644 index 0000000000..b697edfb05 --- /dev/null +++ b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/handler/NetconfXMLToMessageDecoder.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.controller.netconf.util.handler; + +import java.io.ByteArrayInputStream; +import java.nio.ByteBuffer; +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 { + private static final Logger LOG = LoggerFactory.getLogger(NetconfXMLToMessageDecoder.class); + + @Override + @VisibleForTesting + public void decode(ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception { + if (in.readableBytes() == 0) { + LOG.debug("No more content in incoming buffer."); + return; + } + + in.markReaderIndex(); + try { + 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(); + } + } + + 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); + } + +} diff --git a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/handler/ssh/virtualsocket/VirtualSocketException.java b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/handler/ssh/virtualsocket/VirtualSocketException.java index 46fdbb83e7..5907ea8f13 100644 --- a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/handler/ssh/virtualsocket/VirtualSocketException.java +++ b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/handler/ssh/virtualsocket/VirtualSocketException.java @@ -12,4 +12,5 @@ package org.opendaylight.controller.netconf.util.handler.ssh.virtualsocket; * Exception class which provides notification about exceptional situations at the virtual socket layer. */ public class VirtualSocketException extends RuntimeException { + private static final long serialVersionUID = 1L; } diff --git a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/mapping/AbstractNetconfOperation.java b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/mapping/AbstractNetconfOperation.java index 86081b7f81..ba6364662c 100644 --- a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/mapping/AbstractNetconfOperation.java +++ b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/mapping/AbstractNetconfOperation.java @@ -8,6 +8,8 @@ package org.opendaylight.controller.netconf.util.mapping; +import java.util.Map; + import org.opendaylight.controller.netconf.api.NetconfDocumentedException; import org.opendaylight.controller.netconf.api.NetconfOperationRouter; import org.opendaylight.controller.netconf.mapping.api.HandlingPriority; @@ -20,8 +22,6 @@ import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; -import java.util.Map; - public abstract class AbstractNetconfOperation implements NetconfOperation { private final String netconfSessionIdForReporting; @@ -29,7 +29,7 @@ public abstract class AbstractNetconfOperation implements NetconfOperation { this.netconfSessionIdForReporting = netconfSessionIdForReporting; } - public String getNetconfSessionIdForReporting() { + public final String getNetconfSessionIdForReporting() { return netconfSessionIdForReporting; } @@ -67,7 +67,7 @@ public abstract class AbstractNetconfOperation implements NetconfOperation { protected abstract HandlingPriority canHandle(String operationName, String netconfOperationNamespace); @Override - public Document handle(Document message, NetconfOperationRouter opRouter) throws NetconfDocumentedException { + public final Document handle(Document message, NetconfOperationRouter opRouter) throws NetconfDocumentedException { XmlElement requestElement = getRequestElementWithCheck(message); diff --git a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/messages/NetconfHelloMessage.java b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/messages/NetconfHelloMessage.java new file mode 100644 index 0000000000..249f894340 --- /dev/null +++ b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/messages/NetconfHelloMessage.java @@ -0,0 +1,53 @@ +/* + * 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.messages; + +import org.opendaylight.controller.netconf.api.NetconfMessage; +import org.opendaylight.controller.netconf.util.xml.XmlElement; +import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants; +import org.opendaylight.controller.netconf.util.xml.XmlUtil; +import org.w3c.dom.Document; + +import com.google.common.base.Optional; + +/** + * NetconfMessage that can carry additional header with session metadata. See {@link org.opendaylight.controller.netconf.util.messages.NetconfHelloMessageAdditionalHeader} + */ +public final class NetconfHelloMessage extends NetconfMessage { + + public static final String HELLO_TAG = "hello"; + + private final NetconfHelloMessageAdditionalHeader additionalHeader; + + public NetconfHelloMessage(Document doc, NetconfHelloMessageAdditionalHeader additionalHeader) { + super(doc); + checkHelloMessage(doc); + this.additionalHeader = additionalHeader; + } + + public NetconfHelloMessage(Document doc) { + this(doc, null); + } + + public Optional getAdditionalHeader() { + return additionalHeader== null ? Optional.absent() : Optional.of(additionalHeader); + } + + private static void checkHelloMessage(Document doc) { + try { + XmlElement.fromDomElementWithExpected(doc.getDocumentElement(), HELLO_TAG, + XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0); + + } catch (IllegalArgumentException | IllegalStateException e) { + throw new IllegalArgumentException(String.format( + "Hello message invalid format, should contain %s tag from namespace %s, but is: %s", HELLO_TAG, + XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0, XmlUtil.toString(doc)), e); + } + } +} diff --git a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/messages/NetconfHelloMessageAdditionalHeader.java b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/messages/NetconfHelloMessageAdditionalHeader.java new file mode 100644 index 0000000000..f3ca30d2c4 --- /dev/null +++ b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/messages/NetconfHelloMessageAdditionalHeader.java @@ -0,0 +1,121 @@ +/* + * 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.messages; + +import com.google.common.base.Preconditions; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Additional header can be used with hello message to carry information about + * session's connection. Provided information can be reported via netconf + * monitoring. + *
+ * 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
+ * transport - tcp, ssh
+ * session-identifier - persister, client
+ * Session-identifier is optional, others mandatory.
+ * 
+ * This header is inserted in front of a netconf hello message followed by a newline. + */ +public class NetconfHelloMessageAdditionalHeader { + + private static final String SC = ";"; + + private final String userName; + private final String hostAddress; + private final String port; + private final String transport; + private final String sessionIdentifier; + + public NetconfHelloMessageAdditionalHeader(String userName, String hostAddress, String port, String transport, String sessionIdentifier) { + this.userName = userName; + this.hostAddress = hostAddress; + this.port = port; + this.transport = transport; + this.sessionIdentifier = sessionIdentifier; + } + + public String getUserName() { + return userName; + } + + public String getAddress() { + return hostAddress; + } + + public String getPort() { + return port; + } + + public String getTransport() { + return transport; + } + + public String getSessionIdentifier() { + return sessionIdentifier; + } + + /** + * Format additional header into a string suitable as a prefix for netconf hello message + */ + public String toFormattedString() { + Preconditions.checkNotNull(userName); + Preconditions.checkNotNull(hostAddress); + Preconditions.checkNotNull(port); + Preconditions.checkNotNull(transport); + Preconditions.checkNotNull(sessionIdentifier); + return "[" + userName + SC + hostAddress + ":" + port + SC + transport + SC + sessionIdentifier + SC + "]" + + System.lineSeparator(); + } + + @Override + public String toString() { + final StringBuffer sb = new StringBuffer("NetconfHelloMessageAdditionalHeader{"); + sb.append("userName='").append(userName).append('\''); + sb.append(", hostAddress='").append(hostAddress).append('\''); + sb.append(", port='").append(port).append('\''); + sb.append(", transport='").append(transport).append('\''); + sb.append(", sessionIdentifier='").append(sessionIdentifier).append('\''); + sb.append('}'); + return sb.toString(); + } + + // TODO IPv6 + private static final Pattern pattern = Pattern + .compile("\\[(?[^;]+);(?
[0-9\\.]+)[:/](?[0-9]+);(?[a-z]+)[^\\]]+\\]"); + private static final Pattern customHeaderPattern = Pattern + .compile("\\[(?[^;]+);(?
[0-9\\.]+)[:/](?[0-9]+);(?[a-z]+);(?[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); + Preconditions.checkArgument(matcher.matches(), "Additional header in wrong format %s, expected %s", + additionalHeader, pattern); + + String username = matcher.group("username"); + String address = matcher.group("address"); + String port = matcher.group("port"); + String transport = matcher.group("transport"); + String sessionIdentifier = "client"; + if (matcher2.matches()) { + sessionIdentifier = matcher2.group("sessionIdentifier"); + } + return new NetconfHelloMessageAdditionalHeader(username, address, port, transport, sessionIdentifier); + } + +} diff --git a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/messages/NetconfMessageAdditionalHeader.java b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/messages/NetconfMessageAdditionalHeader.java deleted file mode 100644 index 457e226e01..0000000000 --- a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/messages/NetconfMessageAdditionalHeader.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v1.0 which accompanies this distribution, - * and is available at http://www.eclipse.org/legal/epl-v10.html - */ - -package org.opendaylight.controller.netconf.util.messages; - -import com.google.common.base.Optional; -import com.google.common.base.Preconditions; - -/** - * Additional header can be used with hello message to carry information about - * session's connection. Provided information can be reported via netconf - * monitoring. - *
- * 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
- * transport - tcp, ssh
- * session-identifier - persister, client
- * Session-identifier is optional, others mandatory.
- * 
- */ -public class NetconfMessageAdditionalHeader { - - private static final String SC = ";"; - - public static String toString(String userName, String hostAddress, String port, String transport, - Optional sessionIdentifier) { - Preconditions.checkNotNull(userName); - Preconditions.checkNotNull(hostAddress); - Preconditions.checkNotNull(port); - Preconditions.checkNotNull(transport); - String identifier = sessionIdentifier.isPresent() ? sessionIdentifier.get() : ""; - return "[" + userName + SC + hostAddress + ":" + port + SC + transport + SC + identifier + SC + "]" - + System.lineSeparator(); - } -} diff --git a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/messages/NetconfMessageFactory.java b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/messages/NetconfMessageFactory.java deleted file mode 100644 index 6f86cc37f9..0000000000 --- a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/messages/NetconfMessageFactory.java +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v1.0 which accompanies this distribution, - * and is available at http://www.eclipse.org/legal/epl-v10.html - */ - -package org.opendaylight.controller.netconf.util.messages; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.nio.ByteBuffer; -import java.util.Arrays; -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.opendaylight.protocol.framework.DeserializerException; -import org.opendaylight.protocol.framework.DocumentedException; -import org.opendaylight.protocol.framework.ProtocolMessageFactory; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.w3c.dom.Comment; -import org.w3c.dom.Document; -import org.xml.sax.SAXException; - -import com.google.common.base.Charsets; -import com.google.common.base.Optional; -import com.google.common.collect.ImmutableList; - -/** - * NetconfMessageFactory for (de)serializing DOM documents. - */ -public final class NetconfMessageFactory implements ProtocolMessageFactory { - - private static final Logger logger = LoggerFactory.getLogger(NetconfMessageFactory.class); - private static final List POSSIBLE_STARTS = ImmutableList.of( - "[".getBytes(Charsets.UTF_8), "\r\n[".getBytes(Charsets.UTF_8), "\n[".getBytes(Charsets.UTF_8)); - private static final List POSSIBLE_ENDS = ImmutableList.of( - "]\n".getBytes(Charsets.UTF_8), "]\r\n".getBytes(Charsets.UTF_8)); - - private final Optional clientId; - - public NetconfMessageFactory() { - clientId = Optional.absent(); - } - - public NetconfMessageFactory(Optional clientId) { - this.clientId = clientId; - } - - @Override - public NetconfMessage parse(byte[] bytes) throws DeserializerException, DocumentedException { - logMessage(bytes); - - 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); - } - } - NetconfMessage message; - try { - Document doc = XmlUtil.readXmlToDocument(new ByteArrayInputStream(bytes)); - message = new NetconfMessage(doc, additionalHeader); - } catch (final SAXException | IOException | IllegalStateException e) { - throw new NetconfDeserializerException("Could not parse message from " + new String(bytes), e); - } - return message; - } - - private static int findByteSequence(final byte[] bytes, final byte[] sequence) { - if (bytes.length < sequence.length) { - throw new IllegalArgumentException("Sequence to be found is longer than the given byte array."); - } - if (bytes.length == sequence.length) { - if (Arrays.equals(bytes, sequence)) { - return 0; - } else { - return -1; - } - } - int j = 0; - for (int i = 0; i < bytes.length; i++) { - if (bytes[i] == sequence[j]) { - j++; - if (j == sequence.length) { - return i - j + 1; - } - } else { - j = 0; - } - } - return -1; - } - - private int getAdditionalHeaderEndIndex(byte[] bytes) { - for (byte[] possibleEnd : POSSIBLE_ENDS) { - int idx = findByteSequence(bytes, possibleEnd); - - if (idx != -1) { - return idx; - } - } - - return -1; - } - - private boolean startsWithAdditionalHeader(byte[] bytes) { - for (byte[] possibleStart : POSSIBLE_STARTS) { - int i = 0; - for (byte b : possibleStart) { - if(bytes[i] != b) - break; - - return true; - } - } - - return false; - }; - - private void logMessage(byte[] bytes) { - String s = Charsets.UTF_8.decode(ByteBuffer.wrap(bytes)).toString(); - logger.debug("Parsing message \n{}", s); - } - - private String additionalHeaderToString(byte[] bytes) { - return Charsets.UTF_8.decode(ByteBuffer.wrap(bytes)).toString(); - } - - @Override - public byte[] put(NetconfMessage netconfMessage) { - if (clientId.isPresent()) { - Comment comment = netconfMessage.getDocument().createComment("clientId:" + clientId.get()); - netconfMessage.getDocument().appendChild(comment); - } - ByteBuffer msgBytes; - if(netconfMessage.getAdditionalHeader().isPresent()) { - String header = netconfMessage.getAdditionalHeader().get(); - logger.trace("Header of netconf message parsed \n{}", header); - msgBytes = Charsets.UTF_8.encode(header + xmlToString(netconfMessage.getDocument())); - } else { - msgBytes = Charsets.UTF_8.encode(xmlToString(netconfMessage.getDocument())); - } - String content = xmlToString(netconfMessage.getDocument()); - - logger.trace("Putting message \n{}", content); - byte[] b = new byte[msgBytes.limit()]; - msgBytes.get(b); - return b; - } - - private String xmlToString(Document doc) { - return XmlUtil.toString(doc, false); - } -} diff --git a/opendaylight/netconf/netconf-util/src/test/java/org/opendaylight/controller/netconf/util/messages/NetconfMessageFactoryTest.java b/opendaylight/netconf/netconf-util/src/test/java/org/opendaylight/controller/netconf/util/messages/NetconfMessageFactoryTest.java index f8c90836b9..6b7bffcd86 100644 --- a/opendaylight/netconf/netconf-util/src/test/java/org/opendaylight/controller/netconf/util/messages/NetconfMessageFactoryTest.java +++ b/opendaylight/netconf/netconf-util/src/test/java/org/opendaylight/controller/netconf/util/messages/NetconfMessageFactoryTest.java @@ -7,19 +7,27 @@ */ package org.opendaylight.controller.netconf.util.messages; -import com.google.common.io.Files; -import org.junit.Test; +import static org.junit.Assert.assertEquals; +import io.netty.buffer.Unpooled; import java.io.File; +import java.util.ArrayList; +import java.util.List; -public class NetconfMessageFactoryTest { +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 { - NetconfMessageFactory parser = new NetconfMessageFactory(); + NetconfXMLToMessageDecoder parser = new NetconfXMLToHelloMessageDecoder(); File authHelloFile = new File(getClass().getResource("/netconfMessages/client_hello_with_auth.xml").getFile()); - parser.parse(Files.toByteArray(authHelloFile)); + final List out = new ArrayList<>(); + parser.decode(null, Unpooled.wrappedBuffer(Files.toByteArray(authHelloFile)), out); + assertEquals(1, out.size()); } } diff --git a/opendaylight/networkconfiguration/neutron/implementation/pom.xml b/opendaylight/networkconfiguration/neutron/implementation/pom.xml index 83e251aed8..821ac92021 100644 --- a/opendaylight/networkconfiguration/neutron/implementation/pom.xml +++ b/opendaylight/networkconfiguration/neutron/implementation/pom.xml @@ -34,7 +34,6 @@ ${sitedeploy} - org.opendaylight.controller networkconfig.neutron.implementation 0.4.2-SNAPSHOT bundle diff --git a/opendaylight/networkconfiguration/neutron/pom.xml b/opendaylight/networkconfiguration/neutron/pom.xml index fc728dc89f..27588b8bee 100644 --- a/opendaylight/networkconfiguration/neutron/pom.xml +++ b/opendaylight/networkconfiguration/neutron/pom.xml @@ -33,7 +33,6 @@ ${sitedeploy} - org.opendaylight.controller networkconfig.neutron 0.4.2-SNAPSHOT bundle diff --git a/opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/NeutronSubnet.java b/opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/NeutronSubnet.java index 11a1be2118..6582d8c021 100644 --- a/opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/NeutronSubnet.java +++ b/opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/NeutronSubnet.java @@ -269,22 +269,26 @@ public class NeutronSubnet extends ConfigurationObject implements Serializable { } gatewayIPAssigned = false; dnsNameservers = new ArrayList(); - allocationPools = new ArrayList(); - hostRoutes = new ArrayList(); - try { - SubnetUtils util = new SubnetUtils(cidr); - SubnetInfo info = util.getInfo(); - if (gatewayIP == null) { - gatewayIP = info.getLowAddress(); - } - if (allocationPools.size() < 1) { - NeutronSubnet_IPAllocationPool source = - new NeutronSubnet_IPAllocationPool(info.getLowAddress(), - info.getHighAddress()); - allocationPools = source.splitPool(gatewayIP); + if (hostRoutes == null) { + hostRoutes = new ArrayList(); + } + if (allocationPools == null) { + allocationPools = new ArrayList(); + try { + SubnetUtils util = new SubnetUtils(cidr); + SubnetInfo info = util.getInfo(); + if (gatewayIP == null) { + gatewayIP = info.getLowAddress(); + } + if (allocationPools.size() < 1) { + NeutronSubnet_IPAllocationPool source = + new NeutronSubnet_IPAllocationPool(info.getLowAddress(), + info.getHighAddress()); + allocationPools = source.splitPool(gatewayIP); + } + } catch (Exception e) { + return false; } - } catch (Exception e) { - return false; } return true; } diff --git a/opendaylight/northbound/containermanager/pom.xml b/opendaylight/northbound/containermanager/pom.xml index 2d980910f4..48dee485ae 100644 --- a/opendaylight/northbound/containermanager/pom.xml +++ b/opendaylight/northbound/containermanager/pom.xml @@ -14,7 +14,6 @@ HEAD - org.opendaylight.controller containermanager.northbound 0.4.2-SNAPSHOT bundle diff --git a/opendaylight/northbound/integrationtest/pom.xml b/opendaylight/northbound/integrationtest/pom.xml index a6b3855d1f..2789526668 100644 --- a/opendaylight/northbound/integrationtest/pom.xml +++ b/opendaylight/northbound/integrationtest/pom.xml @@ -14,7 +14,6 @@ HEAD - org.opendaylight.controller northbound.integrationtest 0.4.2-SNAPSHOT diff --git a/opendaylight/northbound/networkconfiguration/neutron/pom.xml b/opendaylight/northbound/networkconfiguration/neutron/pom.xml index a6596f886d..7590a976b6 100644 --- a/opendaylight/northbound/networkconfiguration/neutron/pom.xml +++ b/opendaylight/northbound/networkconfiguration/neutron/pom.xml @@ -34,7 +34,6 @@ ${sitedeploy} - org.opendaylight.controller networkconfig.neutron.northbound 0.4.2-SNAPSHOT bundle diff --git a/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronPortsNorthbound.java b/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronPortsNorthbound.java index 642b3bb197..c26e0229d0 100644 --- a/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronPortsNorthbound.java +++ b/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronPortsNorthbound.java @@ -60,6 +60,8 @@ import org.opendaylight.controller.sal.utils.ServiceHelper; @Path("/ports") public class NeutronPortsNorthbound { + final String mac_regex="^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$"; + private NeutronPort extractFields(NeutronPort o, List fields) { return o.extractFields(fields); } @@ -207,7 +209,7 @@ public class NeutronPortsNorthbound { return Response.status(404).build(); } if (singleton.getMacAddress() == null || - !singleton.getMacAddress().matches("^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$")) { + !singleton.getMacAddress().matches(mac_regex)) { return Response.status(400).build(); } if (portInterface.macInUse(singleton.getMacAddress())) { @@ -298,7 +300,7 @@ public class NeutronPortsNorthbound { if (!networkInterface.networkExists(test.getNetworkUUID())) { return Response.status(404).build(); } - if (!test.getMacAddress().matches("^([0-9A-F]{2}[:-]){5}([0-9A-F]{2})$")) { + if (!test.getMacAddress().matches(mac_regex)) { return Response.status(400).build(); } if (portInterface.macInUse(test.getMacAddress())) { diff --git a/opendaylight/northbound/switchmanager/src/main/java/org/opendaylight/controller/switchmanager/northbound/SwitchNorthbound.java b/opendaylight/northbound/switchmanager/src/main/java/org/opendaylight/controller/switchmanager/northbound/SwitchNorthbound.java index 8eff06a763..662af723ed 100644 --- a/opendaylight/northbound/switchmanager/src/main/java/org/opendaylight/controller/switchmanager/northbound/SwitchNorthbound.java +++ b/opendaylight/northbound/switchmanager/src/main/java/org/opendaylight/controller/switchmanager/northbound/SwitchNorthbound.java @@ -416,7 +416,7 @@ public class SwitchNorthbound { * {@link org.opendaylight.controller.sal.core.Property} attached to * it. * - *
+     * 
      *
      * Example:
      *
@@ -540,8 +540,10 @@ public class SwitchNorthbound {
      *            Type of the node connector being programmed (Eg. 'OF')
      * @param nodeConnectorId
      *            NodeConnector Identifier as specified by
-     *            {@link org.opendaylight.controller.sal.core.NodeConnector}
-     *            (Eg. '2')
+     *            {@link org.opendaylight.controller.sal.core.NodeConnector}.
+     *            (Eg. '2'). If nodeConnecterId contains forward slash(/),
+     *            replace forward slash with underscore(_) in the URL. (Eg. for
+     *            Ethernet1/2, use Ethernet1_2)
      * @param propertyName
      *            Name of the Property specified by
      *            {@link org.opendaylight.controller.sal.core.Property} and its
@@ -552,7 +554,7 @@ public class SwitchNorthbound {
      *            extended classes
      * @return Response as dictated by the HTTP Response Status code
      *
-     *         
+     * 
      *
      * Example:
      *
@@ -592,6 +594,10 @@ public class SwitchNorthbound {
         handleNodeAvailability(containerName, nodeType, nodeId);
         Node node = Node.fromString(nodeType, nodeId);
 
+        if (nodeConnectorId.contains("_")) {
+            nodeConnectorId = nodeConnectorId.replace("_", "/");
+        }
+
         handleNodeConnectorAvailability(containerName, node, nodeConnectorType, nodeConnectorId);
         NodeConnector nc = NodeConnector.fromStringNoNode(nodeConnectorType, nodeConnectorId, node);
 
@@ -625,14 +631,16 @@ public class SwitchNorthbound {
      * @param nodeConnectorId
      *            NodeConnector Identifier as specified by
      *            {@link org.opendaylight.controller.sal.core.NodeConnector}
-     *            (Eg. '1')
+     *            (Eg. '1'). If nodeConnecterId contains forward slash(/),
+     *            replace forward slash with underscore(_) in the URL. (Eg. for
+     *            Ethernet1/2, use Ethernet1_2)
      * @param propertyName
      *            Name of the Property specified by
      *            {@link org.opendaylight.controller.sal.core.Property} and its
      *            extended classes. Property that can be deleted is bandwidth
      * @return Response as dictated by the HTTP Response Status code
      *
-     *         
+     * 
      *
      * Example:
      *
@@ -670,6 +678,10 @@ public class SwitchNorthbound {
         handleNodeAvailability(containerName, nodeType, nodeId);
         Node node = Node.fromString(nodeType, nodeId);
 
+        if (nodeConnectorId.contains("_")) {
+            nodeConnectorId = nodeConnectorId.replace("_", "/");
+        }
+
         handleNodeConnectorAvailability(containerName, node, nodeConnectorType, nodeConnectorId);
         NodeConnector nc = NodeConnector.fromStringNoNode(nodeConnectorType, nodeConnectorId, node);
         Status ret = switchManager.removeNodeConnectorProp(nc, propertyName);
diff --git a/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/internal/Controller.java b/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/internal/Controller.java
index 72ee7a679b..63dd0bc29a 100644
--- a/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/internal/Controller.java
+++ b/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/internal/Controller.java
@@ -48,6 +48,7 @@ public class Controller implements IController, CommandProvider, IPluginInConnec
             .getLogger(Controller.class);
     private ControllerIO controllerIO;
     private Thread switchEventThread;
+    private volatile boolean shutdownSwitchEventThread;// default to false
     private ConcurrentHashMap switches;
     private PriorityBlockingQueue switchEvents;
     // only 1 message listener per OFType
@@ -69,6 +70,12 @@ public class Controller implements IController, CommandProvider, IPluginInConnec
 
             while (true) {
                 try {
+                    if(shutdownSwitchEventThread) {
+                        // break out of the infinite loop
+                        // if you are shutting down
+                        logger.info("Switch Event Thread is shutting down");
+                        break;
+                    }
                     SwitchEvent ev = switchEvents.take();
                     SwitchEvent.SwitchEventType eType = ev.getEventType();
                     ISwitch sw = ev.getSwitch();
@@ -104,12 +111,14 @@ public class Controller implements IController, CommandProvider, IPluginInConnec
                         logger.error("Unknown switch event {}", eType.ordinal());
                     }
                 } catch (InterruptedException e) {
-                    switchEvents.clear();
-                    return;
+                    // nothing to do except retry
+                } catch (Exception e) {
+                    // log the exception and retry
+                    logger.warn("Exception in Switch Event Thread is {}" ,e);
                 }
             }
+            switchEvents.clear();
         }
-
     }
 
     /**
@@ -167,6 +176,7 @@ public class Controller implements IController, CommandProvider, IPluginInConnec
             ((SwitchHandler) entry.getValue()).stop();
             it.remove();
         }
+        shutdownSwitchEventThread = true;
         switchEventThread.interrupt();
         try {
             controllerIO.shutDown();
diff --git a/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/internal/SecureMessageReadWriteService.java b/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/internal/SecureMessageReadWriteService.java
index d60bcab8b3..aa60f91174 100644
--- a/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/internal/SecureMessageReadWriteService.java
+++ b/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/internal/SecureMessageReadWriteService.java
@@ -407,9 +407,9 @@ public class SecureMessageReadWriteService implements IMessageReadWrite {
         this.myAppData = ByteBuffer
                 .allocate(session.getApplicationBufferSize());
         this.peerAppData = ByteBuffer.allocate(session
-                .getApplicationBufferSize() * 2);
+                .getApplicationBufferSize() * 20);
         this.myNetData = ByteBuffer.allocate(session.getPacketBufferSize());
-        this.peerNetData = ByteBuffer.allocate(session.getPacketBufferSize() * 2);
+        this.peerNetData = ByteBuffer.allocate(session.getPacketBufferSize() * 20);
     }
 
     @Override
diff --git a/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/DiscoveryService.java b/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/DiscoveryService.java
index 394be07dee..b29ce15f56 100644
--- a/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/DiscoveryService.java
+++ b/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/DiscoveryService.java
@@ -391,7 +391,12 @@ public class DiscoveryService implements IInventoryShimExternalListener, IDataPa
 
             updateProdEdge(edge, props);
         } catch (Exception e) {
-            logger.warn("Caught exception ", e);
+            if (logger.isDebugEnabled()) {
+                logger.debug(
+                        "Caught exception while attempting to snoop non controller generated or malformed LLDP frame sent by {} and received on {}: {}",
+                        HexEncode.bytesToHexStringFormat(ethPkt.getSourceMACAddress()), dstNodeConnector,
+                        e.getMessage());
+            }
         }
     }
 
diff --git a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/utils/NetUtils.java b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/utils/NetUtils.java
index 6c3424c616..dc341625af 100644
--- a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/utils/NetUtils.java
+++ b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/utils/NetUtils.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ * Copyright (c) 2013-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,
@@ -482,7 +482,7 @@ public abstract class NetUtils {
      * @return the int variable containing the unsigned byte value
      */
     public static int getUnsignedByte(byte b) {
-        return (b > 0) ? (int) b : (b & 0x7F | 0x80);
+        return b & 0xFF;
     }
 
     /**
@@ -493,7 +493,7 @@ public abstract class NetUtils {
      * @return the int variable containing the unsigned short value
      */
     public static int getUnsignedShort(short s) {
-        return (s > 0) ? (int) s : (s & 0x7FFF | 0x8000);
+        return s & 0xFFFF;
     }
 
     /**
@@ -520,5 +520,4 @@ public abstract class NetUtils {
     public static byte[] getBroadcastMACAddr() {
         return Arrays.copyOf(BroadcastMACAddr, BroadcastMACAddr.length);
     }
-
 }
diff --git a/opendaylight/sal/api/src/test/java/org/opendaylight/controller/sal/utils/NetUtilsTest.java b/opendaylight/sal/api/src/test/java/org/opendaylight/controller/sal/utils/NetUtilsTest.java
index b8bc6fb447..a2b12782ac 100644
--- a/opendaylight/sal/api/src/test/java/org/opendaylight/controller/sal/utils/NetUtilsTest.java
+++ b/opendaylight/sal/api/src/test/java/org/opendaylight/controller/sal/utils/NetUtilsTest.java
@@ -1,6 +1,5 @@
-
 /*
- * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ * Copyright (c) 2013-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,
@@ -449,4 +448,24 @@ public class NetUtilsTest {
         Assert.assertTrue(NetUtils
                 .isIPAddressValid("2001:420:281:1004:407a:57f4:4d15:c355"));
     }
+
+    @Test
+    public void testGetUnsignedByte() {
+        Assert.assertEquals(0,   NetUtils.getUnsignedByte((byte) 0x00));
+        Assert.assertEquals(1,   NetUtils.getUnsignedByte((byte) 0x01));
+        Assert.assertEquals(127, NetUtils.getUnsignedByte((byte) 0x7f));
+
+        Assert.assertEquals(128, NetUtils.getUnsignedByte((byte) 0x80));
+        Assert.assertEquals(255, NetUtils.getUnsignedByte((byte) 0xff));
+    }
+
+    @Test
+    public void testGetUnsignedShort() {
+        Assert.assertEquals(0,     NetUtils.getUnsignedShort((short) 0x0000));
+        Assert.assertEquals(1,     NetUtils.getUnsignedShort((short) 0x0001));
+        Assert.assertEquals(32767, NetUtils.getUnsignedShort((short) 0x7fff));
+
+        Assert.assertEquals(32768, NetUtils.getUnsignedShort((short) 0x8000));
+        Assert.assertEquals(65535, NetUtils.getUnsignedShort((short) 0xffff));
+    }
 }
diff --git a/opendaylight/samples/simpleforwarding/src/main/java/org/opendaylight/controller/samples/simpleforwarding/internal/SimpleBroadcastHandlerImpl.java b/opendaylight/samples/simpleforwarding/src/main/java/org/opendaylight/controller/samples/simpleforwarding/internal/SimpleBroadcastHandlerImpl.java
index fec6bbe6b4..d2016b1f63 100644
--- a/opendaylight/samples/simpleforwarding/src/main/java/org/opendaylight/controller/samples/simpleforwarding/internal/SimpleBroadcastHandlerImpl.java
+++ b/opendaylight/samples/simpleforwarding/src/main/java/org/opendaylight/controller/samples/simpleforwarding/internal/SimpleBroadcastHandlerImpl.java
@@ -48,7 +48,7 @@ public class SimpleBroadcastHandlerImpl implements IBroadcastHandler, IListenDat
 
     protected ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
 
-    BroadcastMode mode = BroadcastMode.BROADCAST_TO_NONINTERNAL;
+    BroadcastMode mode = BroadcastMode.DISABLED;
 
     @Override
     public PacketResult receiveDataPacket(RawPacket inPkt) {
diff --git a/opendaylight/statisticsmanager/implementation/src/main/java/org/opendaylight/controller/statisticsmanager/internal/StatisticsManager.java b/opendaylight/statisticsmanager/implementation/src/main/java/org/opendaylight/controller/statisticsmanager/internal/StatisticsManager.java
index aa6e4ac383..2376b8752f 100644
--- a/opendaylight/statisticsmanager/implementation/src/main/java/org/opendaylight/controller/statisticsmanager/internal/StatisticsManager.java
+++ b/opendaylight/statisticsmanager/implementation/src/main/java/org/opendaylight/controller/statisticsmanager/internal/StatisticsManager.java
@@ -314,9 +314,9 @@ public class StatisticsManager implements IStatisticsManager, IReadServiceListen
             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.
@@ -467,11 +467,8 @@ public class StatisticsManager implements IStatisticsManager, IReadServiceListen
 
     @Override
     public void nodeFlowStatisticsUpdated(Node node, List flowStatsList) {
-        List currentStat = this.flowStatistics.get(node);
-        // Update cache only if changed to avoid unnecessary cache sync operations
-        if (! flowStatsList.equals(currentStat)){
-            this.flowStatistics.put(node, flowStatsList);
-        }
+        // No equality check because duration fields change constantly
+        this.flowStatistics.put(node, flowStatsList);
     }
 
     @Override
diff --git a/opendaylight/switchmanager/api/src/main/java/org/opendaylight/controller/switchmanager/SwitchConfig.java b/opendaylight/switchmanager/api/src/main/java/org/opendaylight/controller/switchmanager/SwitchConfig.java
index 28c811c669..b8d022f30e 100644
--- a/opendaylight/switchmanager/api/src/main/java/org/opendaylight/controller/switchmanager/SwitchConfig.java
+++ b/opendaylight/switchmanager/api/src/main/java/org/opendaylight/controller/switchmanager/SwitchConfig.java
@@ -21,7 +21,7 @@ import org.opendaylight.controller.sal.utils.Status;
 import org.opendaylight.controller.sal.utils.StatusCode;
 
 /**
- * The class describes a switch configuration
+ * The class describes a switch configuration as a collection of properties
  */
 public class SwitchConfig extends ConfigurationObject implements Cloneable, Serializable {
     private static final long serialVersionUID = 1L;
@@ -123,15 +123,20 @@ public class SwitchConfig extends ConfigurationObject implements Cloneable, Seri
     }
 
     private Status validateNodeId() {
-        if (nodeId == null || nodeId.isEmpty()) {
-            return new Status(StatusCode.BADREQUEST, "NodeId cannot be empty");
+        if (nodeId == null || nodeId.trim().isEmpty()) {
+            return new Status(StatusCode.BADREQUEST, "Invalid node id");
         }
         return new Status(StatusCode.SUCCESS);
     }
 
     private Status validateNodeProperties() {
         if (nodeProperties == null) {
-            return new Status(StatusCode.BADREQUEST, "nodeProperties cannot be null");
+            return new Status(StatusCode.BADREQUEST, "Node properties must be specified");
+        }
+        if (nodeProperties.containsKey(Description.propertyName)) {
+            if (!isValidResourceName(((Description)nodeProperties.get(Description.propertyName)).getValue())) {
+                return new Status(StatusCode.BADREQUEST, "Invalid node description");
+            }
         }
         return new Status(StatusCode.SUCCESS);
     }
diff --git a/opendaylight/switchmanager/implementation/src/main/java/org/opendaylight/controller/switchmanager/internal/SwitchManager.java b/opendaylight/switchmanager/implementation/src/main/java/org/opendaylight/controller/switchmanager/internal/SwitchManager.java
index 19f45e63c5..e457fecfed 100644
--- a/opendaylight/switchmanager/implementation/src/main/java/org/opendaylight/controller/switchmanager/internal/SwitchManager.java
+++ b/opendaylight/switchmanager/implementation/src/main/java/org/opendaylight/controller/switchmanager/internal/SwitchManager.java
@@ -1004,7 +1004,8 @@ public class SwitchManager implements ISwitchManager, IConfigurationContainerAwa
             }
         }
 
-        boolean proactiveForwarding = false;
+        boolean forwardingModeChanged = false;
+
         // copy node properties from config
         if (nodeConfigList != null) {
             String nodeId = node.toString();
@@ -1014,7 +1015,7 @@ public class SwitchManager implements ISwitchManager, IConfigurationContainerAwa
                 propMap.putAll(nodeProperties);
                 if (nodeProperties.get(ForwardingMode.name) != null) {
                     ForwardingMode mode = (ForwardingMode) nodeProperties.get(ForwardingMode.name);
-                    proactiveForwarding = mode.isProactive();
+                    forwardingModeChanged = mode.isProactive();
                 }
             }
         }
@@ -1023,28 +1024,35 @@ public class SwitchManager implements ISwitchManager, IConfigurationContainerAwa
             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);
         }
     }
@@ -1054,7 +1062,12 @@ public class SwitchManager implements ISwitchManager, IConfigurationContainerAwa
         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 removeNodeConnectorSet = new HashSet();
         for (Map.Entry> entry : nodeConnectorProps.entrySet()) {
@@ -1149,6 +1162,13 @@ public class SwitchManager implements ISwitchManager, IConfigurationContainerAwa
 
         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);
@@ -1158,6 +1178,7 @@ public class SwitchManager implements ISwitchManager, IConfigurationContainerAwa
                 addNodeConnectorProp(nodeConnector, null);
             }
 
+
             addSpanPort(nodeConnector);
             break;
         case CHANGED:
@@ -2026,9 +2047,9 @@ public class SwitchManager implements ISwitchManager, IConfigurationContainerAwa
         // only add if span is configured on this nodeConnector
         for (SpanConfig conf : getSpanConfigList(nodeConnector.getNode())) {
             if (conf.getPortArrayList().contains(nodeConnector)) {
-                List ncLists = new ArrayList();
-                ncLists.add(nodeConnector);
-                addSpanPorts(nodeConnector.getNode(), ncLists);
+                List ncList = new ArrayList();
+                ncList.add(nodeConnector);
+                addSpanPorts(nodeConnector.getNode(), ncList);
                 return;
             }
         }
@@ -2149,7 +2170,7 @@ public class SwitchManager implements ISwitchManager, IConfigurationContainerAwa
     public Set getConfiguredNotConnectedSwitches() {
         Set configuredNotConnectedSwitches = new HashSet();
         if (this.inventoryService == null) {
-            log.trace("inventory service not avaiable");
+            log.trace("inventory service not available");
             return configuredNotConnectedSwitches;
         }
 
diff --git a/opendaylight/usermanager/api/src/main/java/org/opendaylight/controller/usermanager/AuthenticatedUser.java b/opendaylight/usermanager/api/src/main/java/org/opendaylight/controller/usermanager/AuthenticatedUser.java
index 94200e66e0..809ca134f7 100644
--- a/opendaylight/usermanager/api/src/main/java/org/opendaylight/controller/usermanager/AuthenticatedUser.java
+++ b/opendaylight/usermanager/api/src/main/java/org/opendaylight/controller/usermanager/AuthenticatedUser.java
@@ -10,6 +10,7 @@ package org.opendaylight.controller.usermanager;
 
 import java.io.Serializable;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.Date;
 import java.util.List;
 
@@ -47,7 +48,7 @@ public class AuthenticatedUser implements Serializable {
     }
 
     public List getUserRoles() {
-        return userRoles;
+        return userRoles == null ? Collections. emptyList() : new ArrayList(userRoles);
     }
 
     public void addUserRole(String string) {
diff --git a/opendaylight/usermanager/api/src/test/java/org/opendaylight/controller/usermanager/AuthenticatedUserTest.java b/opendaylight/usermanager/api/src/test/java/org/opendaylight/controller/usermanager/AuthenticatedUserTest.java
index b8a1a98769..d32799e3eb 100644
--- a/opendaylight/usermanager/api/src/test/java/org/opendaylight/controller/usermanager/AuthenticatedUserTest.java
+++ b/opendaylight/usermanager/api/src/test/java/org/opendaylight/controller/usermanager/AuthenticatedUserTest.java
@@ -8,15 +8,15 @@
 
 package org.opendaylight.controller.usermanager;
 
+import java.util.Arrays;
+import java.util.List;
+
 import org.junit.Assert;
 import org.junit.BeforeClass;
 import org.junit.Test;
 import org.opendaylight.controller.sal.authorization.UserLevel;
 import org.springframework.security.core.GrantedAuthority;
 
-import java.util.Arrays;
-import java.util.List;
-
 public class AuthenticatedUserTest {
 
         static String[] roleArray;
@@ -33,7 +33,7 @@ public class AuthenticatedUserTest {
                 user = new AuthenticatedUser("auser");
 
                 Assert.assertFalse(user.getAccessDate().isEmpty());
-                Assert.assertNull(user.getUserRoles());
+        Assert.assertNotNull(user.getUserRoles());
         }
 
         @Test
diff --git a/opendaylight/web/flows/src/main/resources/js/page.js b/opendaylight/web/flows/src/main/resources/js/page.js
index 094562fac0..ab8301bf73 100644
--- a/opendaylight/web/flows/src/main/resources/js/page.js
+++ b/opendaylight/web/flows/src/main/resources/js/page.js
@@ -457,7 +457,8 @@ one.f.flows = {
             var editButton = one.lib.dashlet.button.single("Edit Flow", one.f.flows.id.dashlet.edit, "btn-primary", "btn-mini");
             var $editButton = one.lib.dashlet.button.button(editButton);
             $editButton.click(function() {
-                var $modal = one.f.flows.modal.initialize(true);
+            	var install = flow['flow']['installInHw'];
+                var $modal = one.f.flows.modal.initialize(true,install);
                 $modal.modal().on('shown',function(){
                     var $port = $('#'+one.f.flows.id.modal.form.port);
                     $('#'+one.f.flows.id.modal.form.nodes).trigger("change");
@@ -550,7 +551,7 @@ one.f.flows = {
                 return $p;
             }
         },
-        initialize : function(edit) {
+        initialize : function(edit,install) {
             var h3;
             if(edit) {
                 h3 = "Edit Flow Entry";
@@ -571,7 +572,7 @@ one.f.flows = {
             if (edit) {
                 // bind edit flow button
                 $('#'+one.f.flows.id.modal.edit, $modal).click(function() {
-                    one.f.flows.modal.save($modal, 'true', true);
+                    one.f.flows.modal.save($modal, install, true);
                 });
             } else {
                 // bind add flow button
diff --git a/opendaylight/web/troubleshoot/src/main/java/org/opendaylight/controller/troubleshoot/web/Troubleshoot.java b/opendaylight/web/troubleshoot/src/main/java/org/opendaylight/controller/troubleshoot/web/Troubleshoot.java
index 36b5043dd9..04fbf846b7 100644
--- a/opendaylight/web/troubleshoot/src/main/java/org/opendaylight/controller/troubleshoot/web/Troubleshoot.java
+++ b/opendaylight/web/troubleshoot/src/main/java/org/opendaylight/controller/troubleshoot/web/Troubleshoot.java
@@ -41,6 +41,7 @@ import org.opendaylight.controller.sal.match.Match;
 import org.opendaylight.controller.sal.match.MatchType;
 import org.opendaylight.controller.sal.reader.FlowOnNode;
 import org.opendaylight.controller.sal.reader.NodeConnectorStatistics;
+import org.opendaylight.controller.sal.reader.NodeDescription;
 import org.opendaylight.controller.sal.utils.EtherTypes;
 import org.opendaylight.controller.sal.utils.GlobalConstants;
 import org.opendaylight.controller.sal.utils.HexEncode;
@@ -101,6 +102,30 @@ public class Troubleshoot implements IDaylightWeb {
         return userLevel.ordinal() <= AUTH_LEVEL.ordinal();
     }
 
+    @RequestMapping(value = "/nodeInfo", method = RequestMethod.GET)
+    @ResponseBody
+    public NodeDescription getNodeInfo(HttpServletRequest request, @RequestParam(required = false) String container,
+            @RequestParam(required = true) String nodeId) {
+        List> lines = new ArrayList>();
+        String containerName = (container == null) ? GlobalConstants.DEFAULT.toString() : container;
+
+        // Derive the privilege this user has on the current container
+        String userName = request.getUserPrincipal().getName();
+        Privilege privilege = DaylightWebUtil.getContainerPrivilege(userName, containerName, this);
+
+        if (privilege != Privilege.NONE) {
+            IStatisticsManager statisticsManager = (IStatisticsManager) ServiceHelper
+                    .getInstance(IStatisticsManager.class, containerName, this);
+            if(statisticsManager != null){
+                Node node = Node.fromString(nodeId);
+                NodeDescription nodeDesc = statisticsManager.getNodeDescription(node);
+                return nodeDesc;
+            }
+        }
+
+        return new NodeDescription();
+    }
+
     @RequestMapping(value = "/existingNodes", method = RequestMethod.GET)
     @ResponseBody
     public TroubleshootingJsonBean getExistingNodes(HttpServletRequest request, @RequestParam(required = false) String container) {
diff --git a/opendaylight/web/troubleshoot/src/main/resources/js/page.js b/opendaylight/web/troubleshoot/src/main/resources/js/page.js
index 4bc4c76fc4..09c4666d44 100644
--- a/opendaylight/web/troubleshoot/src/main/resources/js/page.js
+++ b/opendaylight/web/troubleshoot/src/main/resources/js/page.js
@@ -1,8 +1,8 @@
-/* 
- * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved. 
- * 
- * This program and the accompanying materials are made available under the 
- * terms of the Eclipse Public License v1.0 which accompanies this distribution, 
+/*
+ * 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
  *
  */
@@ -63,13 +63,13 @@ $(one.f.menu.right.bottom).each(function(index, value) {
 /**Troubleshoot modules*/
 one.f.troubleshooting = {
     rootUrl: "/controller/web/troubleshoot",
-    rightBottomDashlet: { 
+    rightBottomDashlet: {
         get: function() {
             var $rightBottomDashlet = $("#right-bottom").find(".dashlet");
             return $rightBottomDashlet;
         },
         setDashletHeader: function(label) {
-            $("#right-bottom li a")[0].innerHTML = label; 
+            $("#right-bottom li a")[0].innerHTML = label;
         }
     },
     createTable: function(columnNames, body) {
@@ -92,8 +92,11 @@ one.f.troubleshooting.existingNodes = {
             portsDataGrid: "one_f_troubleshooting_existingNodes_id_portsDataGrid",
             flowsDataGrid: "one_f_troubleshooting_existingNodes_id_flowsDataGrid",
             refreshFlowsButton:"one_f_troubleshooting_existingNodes_id_refreshFlowsButton",
-            refreshPortsButton:"one_f_troubleshooting_existingNodes_id_refreshPortsButton"
-
+            refreshPortsButton:"one_f_troubleshooting_existingNodes_id_refreshPortsButton",
+            modal : {
+                nodeInfo : "one_f_troubleshooting_existingNodes_id_modal_nodeInfo",
+                cancelButton : "one_f_troubleshooting_existingNodes_id_modal_cancelButton",
+            }
         },
         load: {
             main: function($dashlet) {
@@ -171,7 +174,7 @@ one.f.troubleshooting.existingNodes = {
                         $("#" + one.f.troubleshooting.existingNodes.id.portsDataGrid).datagrid({dataSource: dataSource});
                     });
                 } catch(e) {}
-            } 
+            }
         },
         ajax : function(url, callback) {
             $.getJSON(url, function(data) {
@@ -204,7 +207,9 @@ one.f.troubleshooting.existingNodes = {
                     data: data.nodeData,
                     formatter: function(items) {
                         $.each(items, function(index, item) {
-                            item["statistics"] = "Flows" + 
+                            item.nodeName = "" + item.nodeName + ""
+                            item["statistics"] = "Flows" +
                             " Ports";
                         });
                     },
@@ -461,6 +466,46 @@ one.f.troubleshooting.existingNodes = {
                     result.push(tr);
                 });
                 return result;
+            },
+            nodeInfo : function(nodeId){
+                $.getJSON(one.main.constants.address.prefix + "/troubleshoot/nodeInfo?nodeId=" + nodeId, function(content) {
+                    var h3 = 'Node Information'
+
+                    var headers = [ 'Description','Specification'];
+
+                    var attributes = ['table-striped', 'table-bordered', 'table-condensed'];
+                    var $table = one.lib.dashlet.table.table(attributes);
+                    var $thead = one.lib.dashlet.table.header(headers);
+                    $table.append($thead);
+
+                    var footer = [];
+
+                    var cancelButton = one.lib.dashlet.button.single("Cancel",
+                            one.f.troubleshooting.existingNodes.id.modal.nodeInfo, "", "");
+                    var $cancelButton = one.lib.dashlet.button.button(cancelButton);
+                    footer.push($cancelButton);
+
+                    var body = []
+                    $.each(content, function(key, value) {
+                        var tr = {};
+                        var entry = [];
+
+                        entry.push(key);
+                        entry.push(value);
+
+                        tr.entry = entry;
+                        body.push(tr);
+                    });
+                    var $tbody = one.lib.dashlet.table.body(body);
+                    $table.append($tbody);
+
+                    var $modal = one.lib.modal.spawn(one.f.troubleshooting.existingNodes.id.modal.nodeInfo, h3, $table , footer);
+                    $modal.modal();
+
+                    $('#'+one.f.troubleshooting.existingNodes.id.modal.nodeInfo, $modal).click(function() {
+                        $modal.modal('hide');
+                    });
+                });
             }
         }
 };
@@ -488,7 +533,7 @@ one.f.troubleshooting.uptime = {
                 $("#" + one.f.troubleshooting.uptime.id.datagrid).datagrid({dataSource: dataSource});
             });
     },
-    
+
     ajax : {
         main : function(url, requestData, callback) {
             $.getJSON(url, requestData, function(data) {
@@ -496,7 +541,7 @@ one.f.troubleshooting.uptime = {
             });
         }
     },
-    
+
     data: {
         uptimeDataGrid: function(data) {
             var source = new StaticDataSource({
@@ -548,7 +593,7 @@ one.f.troubleshooting.statistics = {
         var $p = $(document.createElement('p'));
         $p.text('Please select a Flow or Ports statistics');
         $p.addClass('text-center').addClass('text-info');
-        
+
         $dashlet.append($none)
             .append($p);
     }