Merge "Bug 2932: NPE on bundle activation"
authorTony Tkacik <ttkacik@cisco.com>
Wed, 29 Apr 2015 16:57:29 +0000 (16:57 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Wed, 29 Apr 2015 16:57:29 +0000 (16:57 +0000)
14 files changed:
opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/api/jmx/CommitStatus.java
opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/dynamicmbean/AnnotationsTest.java
opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/parallelapsp/TestingParallelAPSPConfigMXBean.java
opendaylight/config/yang-jmx-generator-plugin/src/test/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/JMXGeneratorTest.java
opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/attribute/AbstractAttribute.java
opendaylight/config/yang-jmx-generator/src/test/java/org/opendaylight/controller/config/yangjmxgenerator/AbstractYangTest.java
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/JsonNormalizedNodeBodyReader.java
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/BrokerFacade.java
opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/BrokerFacadeTest.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/editconfig/EditConfig.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/osgi/YangStoreSnapshot.java
opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/config/yang/netconf/mdsal/mapper/NetconfMdsalMapperModule.java
opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/client/stress/Parameters.java
opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/client/stress/StressClient.java

index 3b724e8..3fb0604 100644 (file)
@@ -16,7 +16,7 @@ import javax.management.ObjectName;
 @Immutable
 public class CommitStatus {
     private final List<ObjectName> newInstances, reusedInstances,
-    recreatedInstances;
+        recreatedInstances;
 
     /**
      * @param newInstances       newly created instances
index 9391378..853f8c0 100644 (file)
@@ -95,7 +95,7 @@ public class AnnotationsTest {
     static final String SUBCLASS2 = "subclass2";
 
     @ServiceInterfaceAnnotation(value = SIMPLE, osgiRegistrationType = Executor.class,
-    namespace = "ns", revision = "rev", localName = SIMPLE)
+        namespace = "ns", revision = "rev", localName = SIMPLE)
     static interface SimpleSI extends AbstractServiceInterface {
 
     }
@@ -160,7 +160,7 @@ public class AnnotationsTest {
     }
 
     @ServiceInterfaceAnnotation(value = SUBCLASS2, osgiRegistrationType = ExecutorService.class,
-    namespace = "ns", revision = "rev", localName = SUBCLASS2)
+        namespace = "ns", revision = "rev", localName = SUBCLASS2)
 
     static interface SubSI2 extends SubSI {
 
index 830c67c..d838e7b 100644 (file)
@@ -11,7 +11,7 @@ import javax.management.ObjectName;
 import org.opendaylight.controller.config.api.annotations.ServiceInterfaceAnnotation;
 
 @ServiceInterfaceAnnotation(value = TestingParallelAPSPConfigMXBean.NAME, osgiRegistrationType = TestingAPSP.class,
-namespace = "namespace", revision = "rev", localName = TestingParallelAPSPConfigMXBean.NAME)
+    namespace = "namespace", revision = "rev", localName = TestingParallelAPSPConfigMXBean.NAME)
 public interface TestingParallelAPSPConfigMXBean {
 
     static final String NAME = "apsp";
index 3dae004..56cd615 100644 (file)
@@ -561,7 +561,7 @@ public class JMXGeneratorTest extends AbstractGeneratorTest {
 
     private static class SieASTVisitor extends ASTVisitor {
         protected String packageName, descriptionAnotValue, sieAnnotValue,
-        sieAnnotOsgiRegistrationType, type, extnds, javadoc;
+                sieAnnotOsgiRegistrationType, type, extnds, javadoc;
         protected Map<String, String> methodDescriptions = Maps.newHashMap();
 
         @Override
index e6b69fb..d9a6dd0 100644 (file)
@@ -12,7 +12,7 @@ import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
 
 public abstract class AbstractAttribute implements AttributeIfc {
     private final String attributeYangName, upperCaseCammelCase,
-    lowerCaseCammelCase;
+            lowerCaseCammelCase;
     protected final DataSchemaNode node;
 
     private static String getLocalName(DataSchemaNode attrNode) {
index a937af9..c62e1a7 100644 (file)
@@ -34,8 +34,8 @@ public abstract class AbstractYangTest {
     protected Map<String, Module> namesToModules; // are module names globally
                                                   // unique?
     protected Module configModule, rpcContextModule, threadsModule,
-    threadsJavaModule, bgpListenerJavaModule, ietfInetTypesModule,
-    jmxModule, jmxImplModule, testFilesModule, testFiles1Module;
+            threadsJavaModule, bgpListenerJavaModule, ietfInetTypesModule,
+            jmxModule, jmxImplModule, testFilesModule, testFiles1Module;
 
     public static final String EVENTBUS_MXB_NAME = "eventbus";
     public static final String ASYNC_EVENTBUS_MXB_NAME = "async-eventbus";
index 10399ff..4d8463a 100644 (file)
@@ -90,7 +90,7 @@ public class JsonNormalizedNodeBodyReader extends AbstractIdentifierAwareJaxRsPr
             NormalizedNode<?, ?> partialResult = resultHolder.getResult();
             final NormalizedNode<?, ?> result;
 
-            // unwrap result from augmentation and choice nodes on PUT
+            // FIXME: Also II should be updated unwrap result from augmentation and choice nodes on PUT
             if (!isPost()) {
                 while (partialResult instanceof AugmentationNode || partialResult instanceof ChoiceNode) {
                     final Object childNode = ((DataContainerNode) partialResult).getValue().iterator().next();
@@ -98,7 +98,7 @@ public class JsonNormalizedNodeBodyReader extends AbstractIdentifierAwareJaxRsPr
                 }
             }
 
-            if (partialResult instanceof MapNode) {
+            if (partialResult instanceof MapNode && !isPost()) {
                 result = Iterables.getOnlyElement(((MapNode) partialResult).getValue());
             } else {
                 result = partialResult;
index 0378ae4..6a3adcc 100644 (file)
@@ -39,6 +39,7 @@ import org.opendaylight.yangtools.concepts.ListenerRegistration;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
@@ -204,19 +205,36 @@ public class BrokerFacade {
             final YangInstanceIdentifier parentPath, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext) {
         // FIXME: This is doing correct post for container and list children
         //        not sure if this will work for choice case
-        final YangInstanceIdentifier path;
-        if(payload instanceof MapEntryNode) {
-            path = parentPath.node(payload.getNodeType()).node(payload.getIdentifier());
+        if(payload instanceof MapNode) {
+            final YangInstanceIdentifier mapPath = parentPath.node(payload.getIdentifier());
+            final NormalizedNode<?, ?> emptySubtree = ImmutableNodes.fromInstanceId(schemaContext, mapPath);
+            rWTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
+            ensureParentsByMerge(datastore, mapPath, rWTransaction, schemaContext);
+            for(final MapEntryNode child : ((MapNode) payload).getValue()) {
+                final YangInstanceIdentifier childPath = mapPath.node(child.getIdentifier());
+                checkItemDoesNotExists(rWTransaction, datastore, childPath);
+                rWTransaction.put(datastore, childPath, child);
+            }
         } else {
-            path = parentPath.node(payload.getIdentifier());
+            final YangInstanceIdentifier path;
+            if(payload instanceof MapEntryNode) {
+                path = parentPath.node(payload.getNodeType()).node(payload.getIdentifier());
+            } else {
+                path = parentPath.node(payload.getIdentifier());
+            }
+            checkItemDoesNotExists(rWTransaction,datastore, path);
+            ensureParentsByMerge(datastore, path, rWTransaction, schemaContext);
+            rWTransaction.put(datastore, path, payload);
         }
+        return rWTransaction.submit();
+    }
 
-        final ListenableFuture<Optional<NormalizedNode<?, ?>>> futureDatastoreData = rWTransaction.read(datastore, path);
+    private void checkItemDoesNotExists(final DOMDataReadWriteTransaction rWTransaction,final LogicalDatastoreType store, final YangInstanceIdentifier path) {
+        final ListenableFuture<Boolean> futureDatastoreData = rWTransaction.exists(store, path);
         try {
-            final Optional<NormalizedNode<?, ?>> optionalDatastoreData = futureDatastoreData.get();
-            if (optionalDatastoreData.isPresent() && payload.equals(optionalDatastoreData.get())) {
+            if (futureDatastoreData.get()) {
                 final String errMsg = "Post Configuration via Restconf was not executed because data already exists";
-                LOG.trace(errMsg + ":{}", path);
+                LOG.debug(errMsg + ":{}", path);
                 rWTransaction.cancel();
                 throw new RestconfDocumentedException("Data already exists for path: " + path, ErrorType.PROTOCOL,
                         ErrorTag.DATA_EXISTS);
@@ -225,10 +243,6 @@ public class BrokerFacade {
             LOG.trace("It wasn't possible to get data loaded from datastore at path " + path);
         }
 
-        ensureParentsByMerge(datastore, path, rWTransaction, schemaContext);
-        rWTransaction.merge(datastore, path, payload);
-        LOG.trace("Post " + datastore.name() + " via Restconf: {}", path);
-        return rWTransaction.submit();
     }
 
     private CheckedFuture<Void, TransactionCommitFailedException> putDataViaTransaction(
index 6542396..9c5de08 100644 (file)
@@ -197,13 +197,8 @@ public class BrokerFacadeTest {
         @SuppressWarnings("unchecked")
         final CheckedFuture<Void, TransactionCommitFailedException> expFuture = mock(CheckedFuture.class);
 
-        final NormalizedNode<?, ?> dummyNode2 = createDummyNode("dummy:namespace2", "2014-07-01", "dummy local name2");
-
-        when(rwTransaction.read(eq(LogicalDatastoreType.CONFIGURATION), any(YangInstanceIdentifier.class))).thenReturn(
-                wrapDummyNode(dummyNode2));
-
         when(rwTransaction.exists(eq(LogicalDatastoreType.CONFIGURATION), any(YangInstanceIdentifier.class))).thenReturn(
-            wrapExistence(true));
+            wrapExistence(false));
 
 
         when(rwTransaction.submit()).thenReturn(expFuture);
@@ -215,14 +210,16 @@ public class BrokerFacadeTest {
 
         final InOrder inOrder = inOrder(domDataBroker, rwTransaction);
         inOrder.verify(domDataBroker).newReadWriteTransaction();
-        inOrder.verify(rwTransaction).merge(LogicalDatastoreType.CONFIGURATION, instanceID, dummyNode);
+        inOrder.verify(rwTransaction).exists(LogicalDatastoreType.CONFIGURATION, instanceID);
+        inOrder.verify(rwTransaction).put(LogicalDatastoreType.CONFIGURATION, instanceID, dummyNode);
         inOrder.verify(rwTransaction).submit();
     }
 
     @Test(expected = RestconfDocumentedException.class)
     public void testCommitConfigurationDataPostAlreadyExists() {
-        when(rwTransaction.read(eq(LogicalDatastoreType.CONFIGURATION), any(YangInstanceIdentifier.class))).thenReturn(
-                dummyNodeInFuture);
+        final CheckedFuture<Boolean, ReadFailedException> successFuture = Futures.immediateCheckedFuture(Boolean.TRUE);
+        when(rwTransaction.exists(eq(LogicalDatastoreType.CONFIGURATION), any(YangInstanceIdentifier.class))).thenReturn(
+                successFuture);
         try {
             // Schema context is only necessary for ensuring parent structure
             brokerFacade.commitConfigurationDataPost((SchemaContext)null, instanceID, dummyNode);
index 50676c5..8b31a59 100644 (file)
@@ -260,9 +260,9 @@ public class EditConfig extends AbstractConfigNetconfOperation {
     }
 
     public static Map<String/* Namespace from yang file */,
-            Map<String /* Name of module entry from yang file */, ModuleConfig>> transformMbeToModuleConfigs
-    (final BeanReader configRegistryClient, Map<String/* Namespace from yang file */,
-                    Map<String /* Name of module entry from yang file */, ModuleMXBeanEntry>> mBeanEntries) {
+        Map<String /* Name of module entry from yang file */, ModuleConfig>> transformMbeToModuleConfigs (
+            final BeanReader configRegistryClient, Map<String/* Namespace from yang file */,
+            Map<String /* Name of module entry from yang file */, ModuleMXBeanEntry>> mBeanEntries) {
 
         Map<String, Map<String, ModuleConfig>> namespaceToModuleNameToModuleConfig = Maps.newHashMap();
 
index 283ec42..5da5322 100644 (file)
@@ -37,7 +37,7 @@ final class YangStoreSnapshot implements YangStoreContext {
 
 
     private final Map<String /* Namespace from yang file */,
-    Map<String /* Name of module entry from yang file */, ModuleMXBeanEntry>> moduleMXBeanEntryMap;
+        Map<String /* Name of module entry from yang file */, ModuleMXBeanEntry>> moduleMXBeanEntryMap;
 
 
     private final Map<QName, Map<String, ModuleMXBeanEntry>> qNamesToIdentitiesToModuleMXBeanEntries;
index bf41f19..71a424b 100644 (file)
@@ -27,13 +27,13 @@ public class NetconfMdsalMapperModule extends org.opendaylight.controller.config
     @Override
     public java.lang.AutoCloseable createInstance() {
         final MdsalNetconfOperationServiceFactory mdsalNetconfOperationServiceFactory =
-                new MdsalNetconfOperationServiceFactory(getRootSchemaServiceDependency()) {
-                    @Override
-                    public void close() throws Exception {
-                        super.close();
-                        getMapperAggregatorDependency().onRemoveNetconfOperationServiceFactory(this);
-                    }
-                };
+            new MdsalNetconfOperationServiceFactory(getRootSchemaServiceDependency()) {
+                @Override
+                public void close() throws Exception {
+                    super.close();
+                    getMapperAggregatorDependency().onRemoveNetconfOperationServiceFactory(this);
+                }
+            };
         getDomBrokerDependency().registerConsumer(mdsalNetconfOperationServiceFactory);
         getMapperAggregatorDependency().onAddNetconfOperationServiceFactory(mdsalNetconfOperationServiceFactory);
         return mdsalNetconfOperationServiceFactory;
index 6648bd4..7203107 100644 (file)
@@ -52,6 +52,9 @@ public class Parameters {
     @Arg(dest = "msg-timeout")
     public long msgTimeout;
 
+    @Arg(dest = "tcp-header")
+    public String tcpHeader;
+
     static ArgumentParser getParser() {
         final ArgumentParser parser = ArgumentParsers.newArgumentParser("netconf stress client");
 
@@ -122,6 +125,11 @@ public class Parameters {
                 .setDefault(false)
                 .dest("ssh");
 
+        parser.addArgument("--tcp-header")
+                .type(String.class)
+                .required(false)
+                .dest("tcp-header");
+
         // TODO add get-config option instead of edit + commit
         // TODO different edit config content
 
index fe0a0bc..6bf50d2 100644 (file)
@@ -10,7 +10,11 @@ package org.opendaylight.controller.netconf.test.tool.client.stress;
 
 import ch.qos.logback.classic.Level;
 import com.google.common.base.Charsets;
+import com.google.common.base.Function;
+import com.google.common.base.Joiner;
+import com.google.common.base.Splitter;
 import com.google.common.base.Stopwatch;
+import com.google.common.collect.Iterables;
 import com.google.common.collect.Lists;
 import com.google.common.io.Files;
 import io.netty.channel.nio.NioEventLoopGroup;
@@ -19,6 +23,7 @@ import io.netty.util.Timer;
 import io.netty.util.concurrent.GlobalEventExecutor;
 import java.io.IOException;
 import java.net.InetSocketAddress;
+import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeUnit;
@@ -30,6 +35,7 @@ import org.opendaylight.controller.netconf.client.NetconfClientDispatcherImpl;
 import org.opendaylight.controller.netconf.client.NetconfClientSession;
 import org.opendaylight.controller.netconf.client.conf.NetconfClientConfiguration;
 import org.opendaylight.controller.netconf.client.conf.NetconfClientConfigurationBuilder;
+import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessageAdditionalHeader;
 import org.opendaylight.controller.netconf.util.xml.XmlUtil;
 import org.opendaylight.controller.sal.connect.api.RemoteDevice;
 import org.opendaylight.controller.sal.connect.netconf.listener.NetconfDeviceCommunicator;
@@ -82,18 +88,18 @@ public final class StressClient {
         }
     }
 
-    private static final String MSG_ID_PLACEHOLDER = "{MSG_ID}";
     private static final String MSG_ID_PLACEHOLDER_REGEX = "\\{MSG_ID\\}";
+    private static final String PHYS_ADDR_PLACEHOLDER_REGEX = "\\{PHYS_ADDR\\}";
 
     public static void main(final String[] args) {
         final Parameters params = parseArgs(args, Parameters.getParser());
         params.validate();
 
-        // TODO remove
+        // Wait 5 seconds to allow for debugging/profiling
         try {
-            Thread.sleep(10000);
+            Thread.sleep(5000);
         } catch (final InterruptedException e) {
-//            e.printStackTrace();
+            throw new RuntimeException(e);
         }
 
         final ch.qos.logback.classic.Logger root = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
@@ -104,12 +110,8 @@ public final class StressClient {
         final List<NetconfMessage> preparedMessages = Lists.newArrayListWithCapacity(params.editCount);
 
         final String editContentString;
-        boolean needsModification = false;
         try {
             editContentString = Files.toString(params.editContent, Charsets.UTF_8);
-            if(editContentString.contains(MSG_ID_PLACEHOLDER)) {
-                needsModification = true;
-            };
         } catch (IOException e) {
             throw new IllegalArgumentException("Cannot read content of " + params.editContent);
         }
@@ -122,9 +124,12 @@ public final class StressClient {
             final Element editContentElement;
             try {
                 // Insert message id where needed
-                final String specificEditContent = needsModification ?
-                        editContentString.replaceAll(MSG_ID_PLACEHOLDER_REGEX, Integer.toString(i)) :
-                        editContentString;
+                String specificEditContent =
+                        editContentString.replaceAll(MSG_ID_PLACEHOLDER_REGEX, Integer.toString(i));
+
+                // Insert physical address where needed
+                specificEditContent =
+                        specificEditContent.replaceAll(PHYS_ADDR_PLACEHOLDER_REGEX, getMac(i));
 
                 editContentElement = XmlUtil.readXmlToElement(specificEditContent);
                 final Node config = ((Element) msg.getDocumentElement().getElementsByTagName("edit-config").item(0)).
@@ -176,6 +181,23 @@ public final class StressClient {
         }
     }
 
+    private static String getMac(final int i) {
+        final String hex = Integer.toHexString(i);
+        final Iterable<String> macGroups = Splitter.fixedLength(2).split(hex);
+
+        final int additional = 6 - Iterables.size(macGroups);
+        final ArrayList<String> additionalGroups = Lists.newArrayListWithCapacity(additional);
+        for (int j = 0; j < additional; j++) {
+            additionalGroups.add("00");
+        }
+        return Joiner.on(':').join(Iterables.concat(Iterables.transform(macGroups, new Function<String, String>() {
+            @Override
+            public String apply(final String input) {
+                return input.length() == 1 ? input + "0" : input;
+            }
+        }), additionalGroups));
+    }
+
     private static ExecutionStrategy getExecutionStrategy(final Parameters params, final List<NetconfMessage> preparedMessages, final NetconfDeviceCommunicator sessionListener) {
         if(params.async) {
             return new AsyncExecutionStrategy(params, preparedMessages, sessionListener);
@@ -206,6 +228,16 @@ public final class StressClient {
         final NetconfClientConfigurationBuilder netconfClientConfigurationBuilder = NetconfClientConfigurationBuilder.create();
         netconfClientConfigurationBuilder.withSessionListener(sessionListener);
         netconfClientConfigurationBuilder.withAddress(params.getInetAddress());
+        if(params.tcpHeader != null) {
+            final String header = params.tcpHeader.replaceAll("\"", "").trim() + "\n";
+            netconfClientConfigurationBuilder.withAdditionalHeader(new NetconfHelloMessageAdditionalHeader(null, null, null, null, null) {
+                @Override
+                public String toFormattedString() {
+                    LOG.debug("Sending TCP header {}", header);
+                    return header;
+                }
+            });
+        }
         netconfClientConfigurationBuilder.withProtocol(params.ssh ? NetconfClientConfiguration.NetconfClientProtocol.SSH : NetconfClientConfiguration.NetconfClientProtocol.TCP);
         netconfClientConfigurationBuilder.withConnectionTimeoutMillis(20000L);
         netconfClientConfigurationBuilder.withReconnectStrategy(new NeverReconnectStrategy(GlobalEventExecutor.INSTANCE, 5000));

©2013 OpenDaylight, A Linux Foundation Collaborative Project. All Rights Reserved.
OpenDaylight is a registered trademark of The OpenDaylight Project, Inc.
Linux Foundation and OpenDaylight are registered trademarks of the Linux Foundation.
Linux is a registered trademark of Linus Torvalds.