Merge "Do not use InstanceIdentifier.builder()"
authorTony Tkacik <ttkacik@cisco.com>
Mon, 31 Mar 2014 07:23:02 +0000 (07:23 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Mon, 31 Mar 2014 07:23:02 +0000 (07:23 +0000)
77 files changed:
opendaylight/commons/opendaylight/pom.xml
opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/ConfigManagerActivator.java
opendaylight/distribution/opendaylight/src/main/resources/configuration/config.ini
opendaylight/forwardingrulesmanager/api/src/main/java/org/opendaylight/controller/forwardingrulesmanager/FlowConfig.java
opendaylight/md-sal/model/model-flow-statistics/src/main/yang/opendaylight-statistics-types.yang
opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/md/sal/binding/api/BindingDataBroker.java [new file with mode: 0644]
opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/md/sal/binding/api/BindingDataChangeListener.java [new file with mode: 0644]
opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/md/sal/binding/api/BindingDataReadTransaction.java [new file with mode: 0644]
opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/md/sal/binding/api/BindingDataReadWriteTransaction.java [new file with mode: 0644]
opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/md/sal/binding/api/BindingDataWriteTransaction.java [new file with mode: 0644]
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/RpcProviderRegistryImpl.java
opendaylight/md-sal/sal-binding-it/src/main/java/org/opendaylight/controller/test/sal/binding/it/TestHelper.java
opendaylight/md-sal/sal-binding-it/src/test/java/org/opendaylight/controller/test/sal/binding/it/AbstractTest.java
opendaylight/md-sal/sal-common-api/pom.xml
opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/AsyncDataBroker.java [new file with mode: 0644]
opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/AsyncDataChangeEvent.java [new file with mode: 0644]
opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/AsyncDataChangeListener.java [new file with mode: 0644]
opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/AsyncDataTransactionFactory.java [new file with mode: 0644]
opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/AsyncReadTransaction.java [new file with mode: 0644]
opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/AsyncReadWriteTransaction.java [new file with mode: 0644]
opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/AsyncTransaction.java [new file with mode: 0644]
opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/AsyncWriteTransaction.java [new file with mode: 0644]
opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataChangeListener.java
opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/LogicalDatastoreType.java [new file with mode: 0644]
opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/TransactionChain.java
opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/TransactionChainListener.java
opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMDataBroker.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMDataChangeListener.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMDataReadTransaction.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMDataReadWriteTransaction.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMDataWriteTransaction.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/sal/core/spi/data/DOMStore.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/sal/core/spi/data/DOMStoreReadTransaction.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/sal/core/spi/data/DOMStoreReadWriteTransaction.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/sal/core/spi/data/DOMStoreThreePhaseCommitCohort.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/sal/core/spi/data/DOMStoreTransaction.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/sal/core/spi/data/DOMStoreWriteTransaction.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/sal/core/spi/data/package-info.java [new file with mode: 0644]
opendaylight/md-sal/sal-netconf-connector/pom.xml
opendaylight/md-sal/sal-rest-connector/pom.xml
opendaylight/md-sal/samples/toaster-it/src/test/java/org/opendaylight/controller/sample/toaster/it/ToasterTest.java
opendaylight/md-sal/test/sal-rest-connector-it/pom.xml
opendaylight/md-sal/topology-manager/src/main/java/org/opendaylight/md/controller/topology/manager/FlowCapableTopologyProvider.xtend
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/osgi/Activator.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/osgi/NetconfOperationServiceFactoryImpl.java
opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/NetconfMappingTest.java
opendaylight/netconf/config-persister-impl/pom.xml
opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/CapabilityStrippingConfigSnapshotHolder.java
opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/ConfigPersisterNotificationHandler.java
opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/ConfigPusher.java
opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/ConfigPusherConfiguration.java [deleted file]
opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/ConfigPusherConfigurationBuilder.java [deleted file]
opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/Util.java [deleted file]
opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/osgi/ConfigPersisterActivator.java
opendaylight/netconf/config-persister-impl/src/test/java/org/opendaylight/controller/netconf/persist/impl/CapabilityStrippingConfigSnapshotHolderTest.java
opendaylight/netconf/config-persister-impl/src/test/java/org/opendaylight/controller/netconf/persist/impl/osgi/ConfigPersisterTest.java
opendaylight/netconf/config-persister-impl/src/test/java/org/opendaylight/controller/netconf/persist/impl/osgi/MockNetconfEndpoint.java [deleted file]
opendaylight/netconf/config-persister-impl/src/test/java/org/opendaylight/controller/netconf/persist/impl/osgi/MockedBundleContext.java
opendaylight/netconf/config-persister-impl/src/test/java/org/opendaylight/controller/netconf/persist/impl/osgi/TestingExceptionHandler.java
opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/osgi/NetconfOperationRouterImpl.java
opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/osgi/NetconfOperationServiceSnapshot.java
opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/ConcurrentClientsTest.java
opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/NetconfConfigPersisterITTest.java
opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/pax/IdentityRefNetconfTest.java
opendaylight/netconf/netconf-mapping-api/src/main/java/org/opendaylight/controller/netconf/mapping/api/HandlingPriority.java
opendaylight/netconf/netconf-mapping-api/src/main/java/org/opendaylight/controller/netconf/mapping/api/NetconfOperationChainedExecution.java
opendaylight/netconf/netconf-mapping-api/src/main/java/org/opendaylight/controller/netconf/mapping/api/NetconfOperationServiceFactory.java
opendaylight/netconf/netconf-monitoring/src/main/java/org/opendaylight/controller/netconf/monitoring/osgi/NetconfMonitoringActivator.java
opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/NetconfUtil.java
opendaylight/netconf/pom.xml
opendaylight/northbound/networkconfiguration/bridgedomain/src/main/java/org/opendaylight/controller/networkconfig/bridgedomain/northbound/BridgeDomainNorthbound.java
opendaylight/sal/networkconfiguration/api/src/main/java/org/opendaylight/controller/sal/networkconfig/bridgedomain/BridgeDomainConfigServiceException.java [new file with mode: 0644]
opendaylight/sal/networkconfiguration/api/src/main/java/org/opendaylight/controller/sal/networkconfig/bridgedomain/IPluginInBridgeDomainConfigService.java
opendaylight/sal/networkconfiguration/implementation/src/main/java/org/opendaylight/controller/sal/networkconfig/bridgedomain/internal/BridgeDomainConfigService.java
opendaylight/web/devices/src/main/java/org/opendaylight/controller/devices/web/Devices.java
opendaylight/web/flows/src/main/java/org/opendaylight/controller/flows/web/Flows.java
opendaylight/web/flows/src/main/resources/js/page.js

index e05059b4aef212b3475845777356162b847025d5..e7c7bbe6370c1750d88d454c8faffdd4ac2eadae 100644 (file)
@@ -91,7 +91,7 @@
     <commons.httpclient.version>0.1.2-SNAPSHOT</commons.httpclient.version>
     <concepts.version>0.5.2-SNAPSHOT</concepts.version>
     <protocol-framework.version>0.5.0-SNAPSHOT</protocol-framework.version>
-    <netty.version>4.0.10.Final</netty.version>
+    <netty.version>4.0.17.Final</netty.version>
     <commons.io.version>2.4</commons.io.version>
     <bundlescanner.version>0.4.2-SNAPSHOT</bundlescanner.version>
     <usermanager.version>0.4.2-SNAPSHOT</usermanager.version>
index 308b137403fad9ec60b671813c752ebacf083629..6381836af856f06c6eba19eccfaa4529da6c1194 100644 (file)
@@ -14,9 +14,7 @@ import org.opendaylight.controller.config.manager.impl.osgi.mapping.ModuleInfoBu
 import org.opendaylight.controller.config.manager.impl.osgi.mapping.RefreshingSCPModuleInfoRegistry;
 import org.opendaylight.controller.config.manager.impl.util.OsgiRegistrationUtil;
 import org.opendaylight.controller.config.spi.ModuleFactory;
-import org.opendaylight.yangtools.concepts.ObjectRegistration;
 import org.opendaylight.yangtools.sal.binding.generator.impl.ModuleInfoBackedContext;
-import org.opendaylight.yangtools.yang.binding.YangModuleInfo;
 import org.osgi.framework.BundleActivator;
 import org.osgi.framework.BundleContext;
 import org.osgi.util.tracker.ServiceTracker;
@@ -25,7 +23,6 @@ import javax.management.InstanceAlreadyExistsException;
 import javax.management.MBeanServer;
 import java.lang.management.ManagementFactory;
 import java.util.Arrays;
-import java.util.Collection;
 import java.util.List;
 
 import static org.opendaylight.controller.config.manager.impl.util.OsgiRegistrationUtil.registerService;
@@ -57,11 +54,12 @@ public class ConfigManagerActivator implements BundleActivator {
         // track bundles containing factories
         BlankTransactionServiceTracker blankTransactionServiceTracker = new BlankTransactionServiceTracker(
                 configRegistry);
-        ModuleFactoryBundleTracker moduleFactoryBundleTracker = new ModuleFactoryBundleTracker(
+        ModuleFactoryBundleTracker primaryModuleFactoryBundleTracker = new ModuleFactoryBundleTracker(
                 blankTransactionServiceTracker);
 
         // start extensible tracker
-        ExtensibleBundleTracker<Collection<ObjectRegistration<YangModuleInfo>>> bundleTracker = new ExtensibleBundleTracker<>(context, moduleInfoBundleTracker, moduleFactoryBundleTracker);
+        ExtensibleBundleTracker<?> bundleTracker = new ExtensibleBundleTracker<>(context,
+                primaryModuleFactoryBundleTracker, moduleInfoBundleTracker);
         bundleTracker.open();
 
         // register config registry to OSGi
index 0d223b8df2b3381cc26d248a6467da3efb68f1eb..4598bac593269d026bdcf32dd295ecaf5eb2af37 100644 (file)
@@ -49,7 +49,7 @@ netconf.config.persister.2.properties.numberOfBackups=1
 # Set Default start level for framework
 osgi.bundles.defaultStartLevel=4
 # Extra packages to import from the boot class loader
-org.osgi.framework.system.packages.extra=sun.reflect,sun.reflect.misc,sun.misc
+org.osgi.framework.system.packages.extra=sun.reflect,sun.reflect.misc,sun.misc,sun.nio.ch
 # This is not Eclipse App
 eclipse.ignoreApp=true
 # Don't shutdown equinox if the eclipse App has ended,
index 0841485cb179d0a1517658d9ade15ab7fd668f5f..c89cfc1b9e8914148bc58fc6f3a375baca026e53 100644 (file)
@@ -792,6 +792,27 @@ public class FlowConfig extends ConfigurationObject implements Serializable {
                     continue;
                 }
 
+                sstr = Pattern.compile(ActionType.ENQUEUE + "=(.*)").matcher(actiongrp);
+                if (sstr.matches()) {
+                    for (String t : sstr.group(1).split(",")) {
+                        if (t != null) {
+                            String parts[] = t.split(":");
+                            String nc = String.format("%s|%s@%s", node.getType(), parts[0], node.toString());
+                            if (NodeConnector.fromString(nc) == null) {
+                                return new Status(StatusCode.BADREQUEST, String.format("Enqueue port is not valid"));
+                            }
+                            if (parts.length > 1) {
+                                try {
+                                    Integer.parseInt(parts[1]);
+                                } catch (NumberFormatException e) {
+                                    return new Status(StatusCode.BADREQUEST, String.format("Enqueue %s is not in the range 0 - 2147483647", parts[1]));
+                                }
+                            }
+                        }
+                    }
+                    continue;
+                }
+
                 sstr = Pattern.compile(ActionType.SET_VLAN_PCP.toString() + "=(.*)").matcher(actiongrp);
                 if (sstr.matches()) {
                     if ((sstr.group(1) != null) && !isVlanPriorityValid(sstr.group(1))) {
index c4cccc11023f33fd77ba0b27abf15e4d195b155d..19d6eafa789204b252caa2e8da233808dbce150e 100644 (file)
@@ -2,7 +2,7 @@ module opendaylight-statistics-types {
     namespace "urn:opendaylight:model:statistics:types";
     prefix stat-types;
 
-    import ietf-yang-types {prefix yang;}
+    import ietf-yang-types {prefix yang; revision-date "2010-09-24";}
     
     revision "2013-09-25" {
         description "Initial revision of flow service";
diff --git a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/md/sal/binding/api/BindingDataBroker.java b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/md/sal/binding/api/BindingDataBroker.java
new file mode 100644 (file)
index 0000000..c6a9efe
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * 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.binding.api;
+
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+public interface BindingDataBroker extends AsyncDataBroker<InstanceIdentifier<?>, DataObject, BindingDataChangeListener>{
+    @Override
+    BindingDataReadTransaction newReadOnlyTransaction();
+
+    @Override
+    BindingDataReadWriteTransaction newReadWriteTransaction();
+
+    @Override
+    BindingDataWriteTransaction newWriteOnlyTransaction();
+
+    @Override
+    ListenerRegistration<BindingDataChangeListener> registerDataChangeListener(LogicalDatastoreType store,
+            InstanceIdentifier<?> path, BindingDataChangeListener listener, DataChangeScope triggeringScope);
+}
diff --git a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/md/sal/binding/api/BindingDataChangeListener.java b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/md/sal/binding/api/BindingDataChangeListener.java
new file mode 100644 (file)
index 0000000..94ac2d2
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * 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.binding.api;
+
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeListener;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+public interface BindingDataChangeListener extends AsyncDataChangeListener<InstanceIdentifier<?>, DataObject> {
+    @Override
+    void onDataChanged(AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> change);
+}
diff --git a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/md/sal/binding/api/BindingDataReadTransaction.java b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/md/sal/binding/api/BindingDataReadTransaction.java
new file mode 100644 (file)
index 0000000..93df3eb
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * 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.binding.api;
+
+import org.opendaylight.controller.md.sal.common.api.data.AsyncReadTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+import com.google.common.base.Optional;
+import com.google.common.util.concurrent.ListenableFuture;
+
+public interface BindingDataReadTransaction extends AsyncReadTransaction<InstanceIdentifier<?>, DataObject> {
+    @Override
+    ListenableFuture<Optional<DataObject>> read(LogicalDatastoreType store, InstanceIdentifier<?> path);
+}
diff --git a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/md/sal/binding/api/BindingDataReadWriteTransaction.java b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/md/sal/binding/api/BindingDataReadWriteTransaction.java
new file mode 100644 (file)
index 0000000..0dcf020
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * 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.binding.api;
+
+import org.opendaylight.controller.md.sal.common.api.data.AsyncReadWriteTransaction;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+/**
+ * Logical capture of a combination of both {@link BindingDataReadTransaction} and
+ * {@link BindingDataWriteTransaction}.
+ */
+public interface BindingDataReadWriteTransaction extends BindingDataReadTransaction, BindingDataWriteTransaction, AsyncReadWriteTransaction<InstanceIdentifier<?>, DataObject> {
+
+}
diff --git a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/md/sal/binding/api/BindingDataWriteTransaction.java b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/md/sal/binding/api/BindingDataWriteTransaction.java
new file mode 100644 (file)
index 0000000..e989f73
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * 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.binding.api;
+
+import org.opendaylight.controller.md.sal.common.api.data.AsyncWriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+public interface BindingDataWriteTransaction extends AsyncWriteTransaction<InstanceIdentifier<?>, DataObject> {
+    @Override
+    void put(LogicalDatastoreType store, InstanceIdentifier<?> path, DataObject data);
+
+    @Override
+    void delete(LogicalDatastoreType store, InstanceIdentifier<?> path);
+}
index e0c7d260b5309c2242045821a1d827ae8931c6f1..542dfa7e7bca61a0fc4ff33e31239c3c3872e73b 100644 (file)
@@ -247,7 +247,8 @@ public class RpcProviderRegistryImpl implements //
 
         public RpcProxyRegistration(Class<T> type, T service, RpcProviderRegistryImpl registry) {
             super(service);
-            serviceType = type;
+            this.serviceType = type;
+            this.registry =  registry;
         }
 
         @Override
index 0a71ef5315ebde5338fbe32ab73f1934b2260f01..ba639ad7c24e4e704a15234949a13431a137f9fc 100644 (file)
@@ -45,6 +45,13 @@ public class TestHelper {
                 bindingAwareSalBundles(),
                 mavenBundle("commons-codec", "commons-codec").versionAsInProject(),
 
+                systemProperty("org.osgi.framework.system.packages.extra").value("sun.nio.ch"),
+                mavenBundle("io.netty", "netty-common").versionAsInProject(), //
+                mavenBundle("io.netty", "netty-buffer").versionAsInProject(), //
+                mavenBundle("io.netty", "netty-handler").versionAsInProject(), //
+                mavenBundle("io.netty", "netty-codec").versionAsInProject(), //
+                mavenBundle("io.netty", "netty-transport").versionAsInProject(), //
+
                 mavenBundle(CONTROLLER, "protocol-framework").versionAsInProject(), //
                 mavenBundle(CONTROLLER, "config-manager").versionAsInProject(), // //
                 mavenBundle("commons-io", "commons-io").versionAsInProject(), //
@@ -64,12 +71,6 @@ public class TestHelper {
 
                 mavenBundle(CONTROLLER, "config-persister-impl").versionAsInProject(), //
 
-                mavenBundle("io.netty", "netty-handler").versionAsInProject(), //
-                mavenBundle("io.netty", "netty-codec").versionAsInProject(), //
-                mavenBundle("io.netty", "netty-buffer").versionAsInProject(), //
-                mavenBundle("io.netty", "netty-transport").versionAsInProject(), //
-                mavenBundle("io.netty", "netty-common").versionAsInProject(), //
-
                 mavenBundle("org.apache.servicemix.bundles", "org.apache.servicemix.bundles.xerces", "2.11.0_1"),
                 mavenBundle("org.eclipse.birt.runtime.3_7_1", "org.apache.xml.resolver", "1.2.0"),
 
index 9ac94e7b8904a3148128ca0f01f6b7d6a72fa5d0..019fc0eb73949a55163c8ddd7b9dcc2bee065037 100644 (file)
@@ -25,6 +25,7 @@ import static org.opendaylight.controller.test.sal.binding.it.TestHelper.junitAn
 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.systemPackages;
 import static org.ops4j.pax.exam.CoreOptions.systemProperty;
 
 @RunWith(PaxExam.class)
@@ -70,6 +71,7 @@ public abstract class AbstractTest {
                 mavenBundle("ch.qos.logback", "logback-core").versionAsInProject(), //
                 mavenBundle("ch.qos.logback", "logback-classic").versionAsInProject(), //
                 systemProperty("osgi.bundles.defaultStartLevel").value("4"),
+                systemPackages("sun.nio.ch"),
 
                 mdSalCoreBundles(),
 
index 126fe8d39eebb2c745ba1a85bf34a2dffca55df1..8798897a1def5063a5e9c7cb501c43c14f80566c 100644 (file)
@@ -1,17 +1,21 @@
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
     <modelVersion>4.0.0</modelVersion>
     <parent>
         <groupId>org.opendaylight.controller</groupId>
         <artifactId>sal-parent</artifactId>
         <version>1.1-SNAPSHOT</version>
     </parent>
+
     <artifactId>sal-common-api</artifactId>
+    <packaging>bundle</packaging>
+
     <scm>
-      <connection>scm:git:ssh://git.opendaylight.org:29418/controller.git</connection>
-      <developerConnection>scm:git:ssh://git.opendaylight.org:29418/controller.git</developerConnection>
-      <url>https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL</url>
-      <tag>HEAD</tag>
-  </scm>
+        <connection>scm:git:ssh://git.opendaylight.org:29418/controller.git</connection>
+        <developerConnection>scm:git:ssh://git.opendaylight.org:29418/controller.git</developerConnection>
+        <url>https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL</url>
+        <tag>HEAD</tag>
+    </scm>
 
     <dependencies>
         <dependency>
@@ -22,6 +26,9 @@
             <groupId>org.opendaylight.yangtools</groupId>
             <artifactId>concepts</artifactId>
         </dependency>
+        <dependency>
+            <groupId>com.google.guava</groupId>
+            <artifactId>guava</artifactId>
+        </dependency>
     </dependencies>
-    <packaging>bundle</packaging>
 </project>
diff --git a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/AsyncDataBroker.java b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/AsyncDataBroker.java
new file mode 100644 (file)
index 0000000..87bbfd3
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * 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.api.data;
+
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.concepts.Path;
+
+public interface AsyncDataBroker<P extends Path<P>, D, L extends AsyncDataChangeListener<P, D>> extends //
+        AsyncDataTransactionFactory<P, D> {
+
+    /**
+     *
+     * Scope of Data Change
+     *
+     * Represents scope of data change (addition, replacement, deletion).
+     *
+     * The terminology for types is reused from LDAP
+     *
+     * @see http://www.idevelopment.info/data/LDAP/LDAP_Resources/SEARCH_Setting_the_SCOPE_Parameter.shtml
+     */
+    public enum DataChangeScope {
+
+       /**
+        * Represents only a direct change of the node, such as replacement of node,
+        * addition or deletion.
+        *
+        */
+       BASE,
+       /**
+        * Represent a change (addition,replacement,deletion)
+        * of the node or one of it's direct childs.
+        *
+        */
+       ONE,
+       /**
+        * Represents a change of the node or any of it's child nodes.
+        *
+        */
+       SUBTREE
+    }
+
+    @Override
+    public AsyncReadTransaction<P, D> newReadOnlyTransaction();
+
+    @Override
+    public AsyncReadWriteTransaction<P,D> newReadWriteTransaction();
+
+    @Override
+    public AsyncWriteTransaction<P, D> newWriteOnlyTransaction();
+
+    /**
+     * Registers {@link DataChangeListener} for Data Change callbacks
+     * which will be triggered on which will be triggered on the store
+     *
+     * @param store Logical store in which listener is registered.
+     * @param path Path (subtree identifier) on which client listener will be invoked.
+     * @param listener Instance of listener which should be invoked on
+     * @param triggeringScope Scope of change which triggers callback.
+     * @return Listener registration of the listener, call {@link ListenerRegistration#close()}
+     *         to stop delivery of change events.
+     */
+    ListenerRegistration<L> registerDataChangeListener(LogicalDatastoreType store, P path, L listener, DataChangeScope triggeringScope);
+}
diff --git a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/AsyncDataChangeEvent.java b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/AsyncDataChangeEvent.java
new file mode 100644 (file)
index 0000000..f612e51
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * 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.api.data;
+
+import java.util.Map;
+import java.util.Set;
+
+import org.opendaylight.yangtools.concepts.Immutable;
+import org.opendaylight.yangtools.concepts.Path;
+
+public interface AsyncDataChangeEvent<P extends Path<P>,D> extends Immutable {
+    /**
+     * Returns a immutable map of paths and newly created objects
+     *
+     * @return map of paths and newly created objects
+     */
+    Map<P, D> getCreatedData();
+
+    /**
+     * Returns a immutable map of paths and respective updated objects after update.
+     *
+     * Original state of the object is in
+     * {@link #getOriginalData()}
+     *
+     * @return map of paths and newly created objects
+     */
+    Map<P, D> getUpdatedData();
+
+    /**
+     * Returns a immutable set of removed paths.
+     *
+     * Original state of the object is in
+     * {@link #getOriginalData()}
+     *
+     * @return set of removed paths
+     */
+    Set<P> getRemovedPaths();
+
+    /**
+     * Return a immutable map of paths and original state of updated and removed objects.
+     *
+     * This map is populated if at changed path was previous object, and captures
+     * state of previous object.
+     *
+     * @return map of paths and original state of updated and removed objects.
+     */
+    Map<P, ? extends D> getOriginalData();
+
+    /**
+     * Returns a  immutable stable view of data state, which
+     * captures state of data store before the reported change.
+     *
+     *
+     * The view is rooted at the point where the listener, to which the event is being delivered, was registered.
+     *
+     * @return Stable view of data before the change happened, rooted at the listener registration path.
+     *
+     */
+    D getOriginalSubtree();
+
+    /**
+     * Returns a immutable stable view of data, which captures state of data store
+     * after the reported change.
+     *
+     * The view is rooted at the point where the listener, to which the event is being delivered, was registered.
+     *
+     * @return Stable view of data after the change happened, rooted at the listener registration path.
+     */
+    D getUpdatedSubtree();
+}
diff --git a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/AsyncDataChangeListener.java b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/AsyncDataChangeListener.java
new file mode 100644 (file)
index 0000000..49f07bc
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * 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.api.data;
+
+import java.util.EventListener;
+
+import org.opendaylight.yangtools.concepts.Path;
+
+public interface AsyncDataChangeListener<P extends Path<P>, D> extends EventListener {
+    /**
+     * Note that this method may be invoked from a shared thread pool, so
+     * implementations SHOULD NOT perform CPU-intensive operations and they
+     * definitely MUST NOT invoke any potentially blocking operations.
+     *
+     * @param change Data Change Event being delivered.
+     */
+    void onDataChanged(AsyncDataChangeEvent<P, D> change);
+}
diff --git a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/AsyncDataTransactionFactory.java b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/AsyncDataTransactionFactory.java
new file mode 100644 (file)
index 0000000..732fed0
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * 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.api.data;
+
+import org.opendaylight.yangtools.concepts.Path;
+
+public interface AsyncDataTransactionFactory<P extends Path<P>, D> {
+
+    AsyncReadTransaction<P, D> newReadOnlyTransaction();
+
+    AsyncReadWriteTransaction<P, D> newReadWriteTransaction();
+
+    AsyncWriteTransaction<P,D> newWriteOnlyTransaction();
+
+}
diff --git a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/AsyncReadTransaction.java b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/AsyncReadTransaction.java
new file mode 100644 (file)
index 0000000..1d1d910
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * 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.api.data;
+
+import java.util.concurrent.Future;
+
+import org.opendaylight.yangtools.concepts.Path;
+
+import com.google.common.base.Optional;
+import com.google.common.util.concurrent.ListenableFuture;
+
+public interface AsyncReadTransaction<P extends Path<P>, D> extends AsyncTransaction<P, D> {
+
+    /**
+     *
+     * Reads data from provided logical data store located at provided path
+     *
+     *
+     * @param store
+     *            Logical data store from which read should occur.
+     * @param path
+     *            Path which uniquely identifies subtree which client want to
+     *            read
+     * @return Listenable Future which contains read result
+     *         <ul>
+     *         <li>If data at supplied path exists the {@link Future#get()}
+     *         returns Optional object containing data
+     *         <li>If data at supplied path does not exists the
+     *         {@link Future#get()} returns {@link Optional#absent()}.
+     *         </ul>
+     */
+    ListenableFuture<Optional<D>> read(LogicalDatastoreType store, P path);
+
+}
diff --git a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/AsyncReadWriteTransaction.java b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/AsyncReadWriteTransaction.java
new file mode 100644 (file)
index 0000000..ce740bf
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * 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.api.data;
+
+import org.opendaylight.yangtools.concepts.Path;
+
+/**
+ * Transaction enabling client to have combined transaction,
+ * which provides read and write capabilities.
+ *
+ *
+ * @param <P> Path Type
+ * @param <D> Data Type
+ */
+public interface AsyncReadWriteTransaction<P extends Path<P>, D> extends AsyncReadTransaction<P, D>,
+        AsyncWriteTransaction<P, D> {
+
+}
diff --git a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/AsyncTransaction.java b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/AsyncTransaction.java
new file mode 100644 (file)
index 0000000..23ca275
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * 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.api.data;
+
+import org.opendaylight.yangtools.concepts.Identifiable;
+import org.opendaylight.yangtools.concepts.Path;
+
+
+/**
+ *
+ * @author
+ *
+ * @param <P> Type of path (subtree identifier), which represents location in tree
+ * @param <D> Type of data (payload), which represents data payload
+ */
+public interface AsyncTransaction<P extends Path<P>,D> extends //
+    Identifiable<Object>,
+    AutoCloseable {
+
+    @Override
+    public Object getIdentifier();
+
+    /**
+     * Closes transaction and releases all resources associated with it.
+     */
+    @Override
+    public void close();
+}
diff --git a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/AsyncWriteTransaction.java b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/AsyncWriteTransaction.java
new file mode 100644 (file)
index 0000000..35b9914
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * 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.api.data;
+
+import java.util.concurrent.Future;
+
+import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
+import org.opendaylight.yangtools.concepts.Path;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+
+public interface AsyncWriteTransaction<P extends Path<P>, D>  extends AsyncTransaction<P, D> {
+    /**
+     * Cancels transaction.
+     *
+     * Transaction could be only cancelled if it's status
+     * is {@link TransactionStatus#NEW} or {@link TransactionStatus#SUBMITED}
+     *
+     * Invoking cancel() on {@link TransactionStatus#FAILED} or {@link TransactionStatus#CANCELED}
+     * will have no effect.
+     *
+     * @throws IllegalStateException If transaction status is {@link TransactionStatus#COMMITED}
+     *
+     */
+    public void cancel();
+
+    /**
+     * Store a piece of data at specified path. This acts as a add / replace operation,
+     * which is to say that whole subtree will be replaced by specified path.
+     *
+     * If you need add or merge of current object with specified use {@link #merge(LogicalDatastoreType, Path, Object)}
+     *
+     * @param store Logical data store which should be modified
+     * @param path Data object path
+     * @param data Data object to be written to specified path
+     * @throws IllegalStateException if the transaction is no longer {@link TransactionStatus#NEW}
+     */
+    public void put(LogicalDatastoreType store, P path, D data);
+
+    /**
+     * Store a piece of data at specified path. This acts as a merge operation,
+     * which is to say that any pre-existing data which is not explicitly
+     * overwritten will be preserved. This means that if you store a container,
+     * its child lists will be merged. Performing the following put operations:
+     *
+     * 1) container { list [ a ] }
+     * 2) container { list [ b ] }
+     *
+     * will result in the following data being present:
+     *
+     * container { list [ a, b ] }
+     *
+     * This also means that storing the container will preserve any augmentations
+     * which have been attached to it.
+     *
+     * If you require an explicit replace operation, use {@link #put(LogicalDatastoreType, Path, Object)} instead.
+     *
+     * @param store Logical data store which should be modified
+     * @param path Data object path
+     * @param data Data object to be written to specified path
+     * @throws IllegalStateException if the transaction is no longer {@link TransactionStatus#NEW}
+     */
+    public void merge(LogicalDatastoreType store, P path, D data);
+
+    /**
+     * Remove a piece of data from specified path. This operation does not fail
+     * if the specified path does not exist.
+     *
+     * @param store Logical data store which should be modified
+     * @param path Data object path
+     * @throws IllegalStateException if the transaction is no longer {@link TransactionStatus#NEW}
+     */
+    public void delete(LogicalDatastoreType store, P path);
+
+    /**
+     *
+     * Closes transaction and resources allocated to the transaction.
+     *
+     * This call does not change Transaction status. Client SHOULD
+     * explicitly {@link #commit()} or {@link #cancel()} transaction.
+     *
+     * @throws IllegalStateException if the transaction has not been
+     *         updated by invoking {@link #commit()} or {@link #cancel()}.
+     */
+    @Override
+    public void close();
+
+    /**
+     * Initiates a commit of modification. This call logically seals the
+     * transaction, preventing any the client from interacting with the
+     * data stores. The transaction is marked as {@link TransactionStatus#SUBMITED}
+     * and enqueued into the data store backed for processing.
+     *
+     * <p>
+     * The successful commit changes the state of the system and may affect
+     * several components.
+     *
+     * <p>
+     * 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 Identifier of the store, where commit should occur.
+     * @return Result of the Commit, containing success information or list of
+     *         encountered errors, if commit was not successful. The Future
+     *         blocks until {@link TransactionStatus#COMMITED} or
+     *         {@link TransactionStatus#FAILED} is reached.
+     * @throws IllegalStateException if the transaction is not {@link TransactionStatus#NEW}
+     */
+    public Future<RpcResult<TransactionStatus>> commit();
+
+}
index 8787a3fe8d82de85bc7e064177501e017d041cca..669baa8d9e96a6601bfe7cbe49cb99d2ffb00233 100644 (file)
@@ -12,6 +12,12 @@ import java.util.EventListener;
 import org.opendaylight.yangtools.concepts.Path;
 
 public interface DataChangeListener<P extends Path<P>, D> extends EventListener {
-
+    /**
+     * Note that this method may be invoked from a shared thread pool, so
+     * implementations SHOULD NOT perform CPU-intensive operations and they
+     * definitely MUST NOT invoke any potentially blocking operations.
+     *
+     * @param change Data Change Event being delivered.
+     **/
     void onDataChanged(DataChangeEvent<P, D> change);
 }
diff --git a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/LogicalDatastoreType.java b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/LogicalDatastoreType.java
new file mode 100644 (file)
index 0000000..d2e41f1
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * 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.api.data;
+
+public enum LogicalDatastoreType {
+
+    /**
+     * Logical atastore representing operational state of the system
+     * and it's components
+     *
+     * This datastore is used to describe operational state of
+     * the system and it's operation related data.
+     *
+     */
+    OPERATIONAL,
+    /**
+     * Logical Datastore representing configuration state of the system
+     * and it's components.
+     *
+     * This datastore is used to describe intended state of
+     * the system and intended operation mode.
+     *
+     */
+    CONFIGURATION
+
+}
index d542935dd6dbf0fdb91ce72b273d6bc9c87b2668..e7e0eb0ff87e424973de4b9c9d6fdf9111ccae4c 100644 (file)
@@ -13,17 +13,34 @@ import org.opendaylight.yangtools.concepts.Path;
  * A chain of transactions. Transactions in a chain need to be committed in sequence and each
  * transaction should see the effects of previous transactions as if they happened. A chain
  * makes no guarantees of atomicity, in fact transactions are committed as soon as possible.
+ *
  */
-public interface TransactionChain<P extends Path<P>, D> extends AutoCloseable {
+public interface TransactionChain<P extends Path<P>, D> extends AutoCloseable, AsyncDataTransactionFactory<P, D> {
+
     /**
-     * Create a new transaction which will continue the chain. The previous transaction
-     * has to be either COMMITTED or CANCELLED.
+     * Create a new read only transaction which will continue the chain.
+     * The previous read-write transaction has to be either COMMITED or CANCELLED.
      *
      * @return New transaction in the chain.
-     * @throws IllegalStateException if the previous transaction was not COMMITTED or CANCELLED.
+     * @throws IllegalStateException if the previous transaction was not COMMITED
+     *    or CANCELLED.
      * @throws TransactionChainClosedException if the chain has been closed.
      */
-    DataModification<P, D> newTransaction();
+    @Override
+    public AsyncReadTransaction<P, D> newReadOnlyTransaction();
+
+
+    /**
+     * Create a new read write transaction which will continue the chain.
+     * The previous read-write transaction has to be either COMMITED or CANCELLED.
+     *
+     * @return New transaction in the chain.
+     * @throws IllegalStateException if the previous transaction was not COMMITTED
+     *    or CANCELLED.
+     * @throws TransactionChainClosedException if the chain has been closed.
+     */
+    @Override
+    public AsyncReadWriteTransaction<P, D> newReadWriteTransaction();
 
     @Override
     void close();
index 4dac6f557ebda436b29d2e1aaea9df86682fb90a..52b0812736af1f236c292b28eefe9fe51db1245c 100644 (file)
@@ -21,7 +21,7 @@ public interface TransactionChainListener extends EventListener {
      * @param transaction Transaction which caused the chain to fail
      * @param cause The cause of transaction failure
      */
-    void onTransactionChainFailed(TransactionChain<?, ?> chain, DataModification<?, ?> transaction, Throwable cause);
+    void onTransactionChainFailed(TransactionChain<?, ?> chain, AsyncTransaction<?, ?> transaction, Throwable cause);
 
     /**
      * Invoked when a transaction chain is completed. A transaction chain is considered completed when it has been
diff --git a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMDataBroker.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMDataBroker.java
new file mode 100644 (file)
index 0000000..5328b79
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * 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.dom.api;
+
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+public interface DOMDataBroker extends AsyncDataBroker<InstanceIdentifier, NormalizedNode<?, ?>, DOMDataChangeListener>{
+    @Override
+    DOMDataReadTransaction newReadOnlyTransaction();
+
+    @Override
+    DOMDataReadWriteTransaction newReadWriteTransaction();
+
+    @Override
+    DOMDataWriteTransaction newWriteOnlyTransaction();
+}
diff --git a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMDataChangeListener.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMDataChangeListener.java
new file mode 100644 (file)
index 0000000..d1f0176
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * 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.dom.api;
+
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeListener;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+public interface DOMDataChangeListener extends AsyncDataChangeListener<InstanceIdentifier, NormalizedNode<?, ?>> {
+
+}
diff --git a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMDataReadTransaction.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMDataReadTransaction.java
new file mode 100644 (file)
index 0000000..5baa5e7
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * 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.dom.api;
+
+import org.opendaylight.controller.md.sal.common.api.data.AsyncReadTransaction;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+public interface DOMDataReadTransaction extends AsyncReadTransaction<InstanceIdentifier, NormalizedNode<?, ?>> {
+
+}
diff --git a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMDataReadWriteTransaction.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMDataReadWriteTransaction.java
new file mode 100644 (file)
index 0000000..55600b0
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * 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.dom.api;
+
+import org.opendaylight.controller.md.sal.common.api.data.AsyncReadWriteTransaction;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+public interface DOMDataReadWriteTransaction extends DOMDataReadTransaction, DOMDataWriteTransaction, AsyncReadWriteTransaction<InstanceIdentifier, NormalizedNode<?, ?>> {
+
+}
diff --git a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMDataWriteTransaction.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMDataWriteTransaction.java
new file mode 100644 (file)
index 0000000..9415973
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * 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.dom.api;
+
+import org.opendaylight.controller.md.sal.common.api.data.AsyncWriteTransaction;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+public interface DOMDataWriteTransaction extends AsyncWriteTransaction<InstanceIdentifier, NormalizedNode<?, ?>> {
+
+}
diff --git a/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/sal/core/spi/data/DOMStore.java b/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/sal/core/spi/data/DOMStore.java
new file mode 100644 (file)
index 0000000..c82a2b8
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * 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.core.spi.data;
+
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeListener;
+import org.opendaylight.controller.md.sal.common.api.data.DataChangeListener;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+public interface DOMStore {
+
+    /**
+     *
+     * Creates a read only transaction
+     *
+     * @return
+     */
+    DOMStoreReadTransaction newReadOnlyTransaction();
+
+    /**
+     * Creates write only transaction
+     *
+     * @return
+     */
+    DOMStoreWriteTransaction newWriteOnlyTransaction();
+
+    /**
+     * Creates Read-Write transaction
+     *
+     * @return
+     */
+    DOMStoreReadWriteTransaction newReadWriteTransaction();
+
+    /**
+     * Registers {@link DataChangeListener} for Data Change callbacks
+     * which will be triggered on the change of provided subpath. What
+     * constitutes a change depends on the @scope parameter.
+     *
+     * Listener upon registration receives an initial callback
+     * {@link AsyncDataChangeListener#onDataChanged(org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent)}
+     * which contains stable view of data tree at the time of registration.
+     *
+     * @param path Path (subtree identifier) on which client listener will be invoked.
+     * @param listener Instance of listener which should be invoked on
+     * @param scope Scope of change which triggers callback.
+     * @return Listener Registration object, which client may use to close registration
+     *         / interest on receiving data changes.
+     *
+     */
+    <L extends AsyncDataChangeListener<InstanceIdentifier, NormalizedNode<?, ?>>> ListenerRegistration<L> registerChangeListener(
+            InstanceIdentifier path, L listener, DataChangeScope scope);
+
+}
diff --git a/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/sal/core/spi/data/DOMStoreReadTransaction.java b/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/sal/core/spi/data/DOMStoreReadTransaction.java
new file mode 100644 (file)
index 0000000..733c109
--- /dev/null
@@ -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.sal.core.spi.data;
+
+import java.util.concurrent.Future;
+
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+import com.google.common.base.Optional;
+import com.google.common.util.concurrent.ListenableFuture;
+
+public interface DOMStoreReadTransaction extends DOMStoreTransaction {
+
+    /**
+     *
+     * Reads data from provided logical data store located at provided path
+     *
+     *
+     * @param path
+     *            Path which uniquely identifies subtree which client want to
+     *            read
+     * @return Listenable Future which contains read result
+     *         <ul>
+     *         <li>If data at supplied path exists the {@link Future#get()}
+     *         returns Optional object containing data
+     *         <li>If data at supplied path does not exists the
+     *         {@link Future#get()} returns {@link Optional#absent()}.
+     *         </ul>
+     */
+    ListenableFuture<Optional<NormalizedNode<?,?>>> read(InstanceIdentifier path);
+}
diff --git a/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/sal/core/spi/data/DOMStoreReadWriteTransaction.java b/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/sal/core/spi/data/DOMStoreReadWriteTransaction.java
new file mode 100644 (file)
index 0000000..7277406
--- /dev/null
@@ -0,0 +1,15 @@
+/*
+ * 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.core.spi.data;
+
+/**
+ * Combination of a {@link DOMStoreReadTransaction} and {@link DOMStoreWriteTransaction}.
+ */
+public interface DOMStoreReadWriteTransaction extends DOMStoreReadTransaction, DOMStoreWriteTransaction {
+
+}
diff --git a/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/sal/core/spi/data/DOMStoreThreePhaseCommitCohort.java b/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/sal/core/spi/data/DOMStoreThreePhaseCommitCohort.java
new file mode 100644 (file)
index 0000000..986a153
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * 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.core.spi.data;
+
+import com.google.common.util.concurrent.ListenableFuture;
+
+/**
+ * Interface implemented by the {@link DOMStore} and exposed for each {@link DOMStoreWriteTransaction}
+ * upon its transition to Ready state. The frontend (DOMStore user) uses this interface to drive the
+ * commit procedure across potentially multiple DOMStores using the Three-Phase-Commit (3PC) Protocol,
+ * as described in {@link https://en.wikipedia.org/wiki/Three-phase_commit}.
+ */
+public interface DOMStoreThreePhaseCommitCohort {
+
+    /**
+     * Sends transaction associated with this three phase commit instance to the
+     * participant, participant votes on the transaction, if the transaction
+     * should be committed or aborted.
+     *
+     * @return ListenableFuture with vote of the participant. Vote
+     *         {@link ListenableFuture#get()} is following:
+     *         <ul>
+     *         <li>
+     *         true if transaction is approved by data store.
+     *         <li>false if the transaction is not approved by data store and
+     *         should be aborted.
+     */
+    ListenableFuture<Boolean> canCommit();
+
+    /**
+     * Initiates a pre-commit phase of associated transaction on datastore.
+     *
+     * This message is valid only and only if and only if the participant responded
+     * on {@link #canCommit()} call with positive response.
+     *
+     * @return ListenableFuture representing acknowledgment for participant
+     *        that pre-commit message was received and processed.
+     */
+    ListenableFuture<Void> preCommit();
+
+    /**
+     * Initiates a abort phase of associated transaction on data store.
+     *
+     * @return ListenableFuture representing acknowledgment for participant
+     *        that abort message was received.
+     */
+    ListenableFuture<Void> abort();
+
+    /**
+     * Initiates a commit phase on of associated transaction on data store.
+     *
+     * @return ListenableFuture representing acknowledgment for participant
+     *        that commit message was received and commit of transaction was
+     *        processed.
+     */
+    ListenableFuture<Void> commit();
+}
diff --git a/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/sal/core/spi/data/DOMStoreTransaction.java b/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/sal/core/spi/data/DOMStoreTransaction.java
new file mode 100644 (file)
index 0000000..76ea78b
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * 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.core.spi.data;
+
+import org.opendaylight.yangtools.concepts.Identifiable;
+
+/**
+ * DOM Data Store transaction
+ *
+ * See {@link DOMStoreReadTransaction}, {@link DOMStoreWriteTransaction} and {@link DOMStoreReadWriteTransaction}
+ * for specific transaction types.
+ *
+ */
+public interface DOMStoreTransaction extends AutoCloseable, Identifiable<Object> {
+    /**
+     * Unique identifier of the transaction
+     */
+    @Override
+    public Object getIdentifier();
+
+    @Override
+    void close();
+}
diff --git a/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/sal/core/spi/data/DOMStoreWriteTransaction.java b/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/sal/core/spi/data/DOMStoreWriteTransaction.java
new file mode 100644 (file)
index 0000000..6761bc1
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * 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.core.spi.data;
+
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.yangtools.concepts.Path;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+public interface DOMStoreWriteTransaction extends DOMStoreTransaction {
+
+    /**
+     * Store a provided data at specified path. This acts as a add / replace
+     * operation, which is to say that whole subtree will be replaced by
+     * specified path.
+     *
+     * If you need add or merge of current object with specified use
+     * {@link #merge(LogicalDatastoreType, Path, Object)}
+     *
+     *
+     * @param path
+     * @param data
+     *            Data object to be written
+     *
+     * @throws IllegalStateException
+     *             if the client code already sealed transaction and invoked
+     *             {@link #ready()}
+     */
+    void write(InstanceIdentifier path, NormalizedNode<?, ?> data);
+
+    /**
+     *
+     * Deletes data and whole subtree located at provided path.
+     *
+     * @param path
+     *            Path to delete
+     * @throws IllegalStateException
+     *             if the client code already sealed transaction and invoked
+     *             {@link #ready()}
+     */
+    void delete(InstanceIdentifier path);
+
+    /**
+     *
+     * Seals transaction, and returns three-phase commit cohort associated
+     * with this transaction and DOM Store to be coordinated by coordinator.
+     *
+     * @return Three Phase Commit Cohort instance for this transaction.
+     */
+    DOMStoreThreePhaseCommitCohort ready();
+
+}
diff --git a/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/sal/core/spi/data/package-info.java b/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/sal/core/spi/data/package-info.java
new file mode 100644 (file)
index 0000000..ec3b698
--- /dev/null
@@ -0,0 +1,8 @@
+/*\r
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.\r
+ *\r
+ * This program and the accompanying materials are made available under the\r
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+ * and is available at http://www.eclipse.org/legal/epl-v10.html\r
+ */\r
+package org.opendaylight.controller.sal.core.spi.data;
\ No newline at end of file
index 777709b06ae122bf3333b7e6a2e9e3e7d84acc49..182441d3f5df53135133505448e4979135126989 100644 (file)
             <groupId>org.opendaylight.yangtools</groupId>
             <artifactId>yang-data-impl</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.opendaylight.yangtools</groupId>
+            <artifactId>yang-parser-impl</artifactId>
+        </dependency>
         <dependency>
             <groupId>org.opendaylight.controller</groupId>
             <artifactId>sal-broker-impl</artifactId>
index cc3b0296ed3ed299ab0ffe5a58b3d2e2775b78bd..4aa3824e615aef1dd528d30a69ae73f39e358de8 100644 (file)
       <groupId>io.netty</groupId>
       <artifactId>netty-codec-http</artifactId>
     </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>sal-remote</artifactId>
+     </dependency>
     
     <!-- Testing Dependencies -->
     <dependency>
index 38a4dd46617405c148022d4622a3b200b9182b80..000783bd07e545ee16ae5e306c20c8d72f4d6e35 100644 (file)
@@ -52,6 +52,7 @@ public class ToasterTest {
                 mavenBundle("ch.qos.logback", "logback-core").versionAsInProject(), //
                 mavenBundle("ch.qos.logback", "logback-classic").versionAsInProject(), //
                 systemProperty("osgi.bundles.defaultStartLevel").value("4"),
+                systemPackages("sun.nio.ch"),
 
                 toasterBundles(),
                 mdSalCoreBundles(),
index 15fee781ef77275a0213e4a842b85ed953ae8eaa..a9fc739456b95740c3ab9c00313c31711e7ebba9 100644 (file)
         <dependency>
             <groupId>io.netty</groupId>
             <artifactId>netty-all</artifactId>
-            <version>4.0.10.Final</version>
+           <version>${netty.version}</version>
             <scope>test</scope>
         </dependency>
         <dependency>
index 036fe733aa80b56ac7cc2302d9a26cab0d2703ac..73e03d1e7d208287c1bed8505f889fbe470c8fa8 100644 (file)
@@ -14,6 +14,7 @@ import org.opendaylight.yangtools.yang.binding.NotificationListener
 import org.slf4j.LoggerFactory
 import org.opendaylight.controller.sal.binding.api.AbstractBindingAwareProvider
 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext
+import org.osgi.framework.BundleContext;
 
 class FlowCapableTopologyProvider extends AbstractBindingAwareProvider implements AutoCloseable {
 
@@ -35,7 +36,11 @@ class FlowCapableTopologyProvider extends AbstractBindingAwareProvider implement
        LOG.info("FlowCapableTopologyProvider stopped.");
         listenerRegistration?.close();
     }
-    
+
+     /**
+       * Gets called on start of a bundle.
+       * @param session
+       */
     override onSessionInitiated(ProviderContext session) {
         dataService = session.getSALService(DataProviderService)
         notificationService = session.getSALService(NotificationProviderService)
@@ -43,6 +48,14 @@ class FlowCapableTopologyProvider extends AbstractBindingAwareProvider implement
         exporter.start();
         listenerRegistration = notificationService.registerNotificationListener(exporter);
     }
+
+    /**
+      * Gets called during stop bundle
+      * @param context The execution context of the bundle being stopped.
+      */
+    override stopImpl(BundleContext context) {
+        close();
+    }
     
 }
 
index b39549ed5b73095f44194a30e15d5b6cdaa182ce..421870ca3611bb6e35a8e7ddd9ec574d0e62e4ab 100644 (file)
@@ -19,6 +19,9 @@ import org.osgi.util.tracker.ServiceTrackerCustomizer;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.util.Dictionary;
+import java.util.Hashtable;
+
 import static com.google.common.base.Preconditions.checkState;
 
 public class Activator implements BundleActivator {
@@ -88,7 +91,9 @@ public class Activator implements BundleActivator {
         public void run() {
             NetconfOperationServiceFactoryImpl factory = new NetconfOperationServiceFactoryImpl(yangStoreService);
             logger.debug("Registering into OSGi");
-            osgiRegistration = context.registerService(NetconfOperationServiceFactory.class, factory, null);
+            Dictionary<String, String> properties = new Hashtable<>();
+            properties.put("name", "config-netconf-connector");
+            osgiRegistration = context.registerService(NetconfOperationServiceFactory.class, factory, properties);
         }
     }
 }
index 4ca71ae2886a143d7322ed67be3a97b6f8a6cfb3..b8b7fcb47f137f5d422c0239f9159cec3c5ad234 100644 (file)
@@ -66,7 +66,7 @@ public class NetconfOperationServiceFactoryImpl implements NetconfOperationServi
     }
 
     @Override
-    public NetconfOperationServiceImpl createService(long netconfSessionId, String netconfSessionIdForReporting) {
+    public NetconfOperationServiceImpl createService(String netconfSessionIdForReporting) {
         try {
             return new NetconfOperationServiceImpl(yangStoreService, jmxClient, netconfSessionIdForReporting);
         } catch (YangStoreException e) {
index b52328f6313f534f522778b8614c22ea1246f76f..8b6b1aefc1971d2af9fbc7f69b4264cc79ed3327 100644 (file)
@@ -52,10 +52,10 @@ import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStore
 import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreSnapshot;
 import org.opendaylight.controller.netconf.confignetconfconnector.transactions.TransactionProvider;
 import org.opendaylight.controller.netconf.impl.mapping.operations.DefaultCloseSession;
-import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationRouterImpl;
 import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceSnapshot;
 import org.opendaylight.controller.netconf.mapping.api.HandlingPriority;
 import org.opendaylight.controller.netconf.mapping.api.NetconfOperation;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationChainedExecution;
 import org.opendaylight.controller.netconf.util.test.XmlFileLoader;
 import org.opendaylight.controller.netconf.util.xml.XmlElement;
 import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
@@ -681,7 +681,7 @@ public class NetconfMappingTest extends AbstractConfigTest {
 
         Preconditions.checkState(priority != HandlingPriority.CANNOT_HANDLE);
 
-        final Document response = op.handle(request, NetconfOperationRouterImpl.EXECUTION_TERMINATION_POINT);
+        final Document response = op.handle(request, NetconfOperationChainedExecution.EXECUTION_TERMINATION_POINT);
         logger.debug("Got response\n{}", XmlUtil.toString(response));
         return response.getDocumentElement();
     }
index c0b9f68814141427098f92304f024021b74dcfb9..7b4511e1f937c3ec7ca63c6643d91ab5d3ba67c1 100644 (file)
             <groupId>${project.groupId}</groupId>
             <artifactId>netconf-api</artifactId>
         </dependency>
-        <dependency>
-            <groupId>${project.groupId}</groupId>
-            <artifactId>netconf-client</artifactId>
-        </dependency>
         <dependency>
             <groupId>${project.groupId}</groupId>
             <artifactId>netconf-util</artifactId>
@@ -61,6 +57,7 @@
         <dependency>
             <groupId>org.opendaylight.yangtools</groupId>
             <artifactId>mockito-configuration</artifactId>
+            <scope>test</scope>
         </dependency>
         <dependency>
             <groupId>commons-io</groupId>
                     <instructions>
                         <Bundle-Activator>org.opendaylight.controller.netconf.persist.impl.osgi.ConfigPersisterActivator
                         </Bundle-Activator>
-                        <Require-Capability>org.opendaylight.controller.config.persister.storage.adapter
-                        </Require-Capability>
-                        <Import-Package>
-                            com.google.common.base,
-                            com.google.common.collect,
-                            javax.management,
-                            javax.xml.parsers,
-                            org.opendaylight.controller.config.persist.api,
-                            org.opendaylight.controller.netconf.api,
-                            org.opendaylight.controller.netconf.api.jmx,
-                            org.opendaylight.controller.netconf.client,
-                            org.opendaylight.controller.netconf.util.osgi,
-                            org.opendaylight.controller.netconf.util.xml,
-                            org.opendaylight.controller.netconf.util.messages,
-                            io.netty.channel,
-                            io.netty.channel.nio,
-                            io.netty.util.concurrent,
-                            org.osgi.framework,
-                            org.slf4j,
-                            org.w3c.dom,
-                            org.xml.sax,
-                            javax.xml.namespace,
-                            javax.xml.xpath,
-                            org.opendaylight.controller.config.api,
-                            org.opendaylight.controller.netconf.util
-                        </Import-Package>
+                        <Require-Capability>org.opendaylight.controller.config.persister.storage.adapter</Require-Capability>
                         <Export-Package>
                         </Export-Package>
                     </instructions>
index d9c5dfadede5a02bcd7d6c0f91fffccda499a14f..ab353e349b2908b67ade7f583f3601b7aa16ce3b 100644 (file)
@@ -5,6 +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.netconf.persist.impl;
 
 import com.google.common.annotations.VisibleForTesting;
@@ -18,54 +19,50 @@ import org.w3c.dom.Element;
 
 import java.util.Collections;
 import java.util.HashSet;
-import java.util.Iterator;
 import java.util.Map.Entry;
 import java.util.Set;
 import java.util.SortedSet;
 import java.util.TreeSet;
-import java.util.regex.Pattern;
-
-import static com.google.common.base.Preconditions.checkState;
 
+/**
+ * Inspects snapshot xml to be stored, remove all capabilities that are not referenced by it.
+ * Useful when persisting current configuration.
+ */
 public class CapabilityStrippingConfigSnapshotHolder implements ConfigSnapshotHolder {
     private static final Logger logger = LoggerFactory.getLogger(CapabilityStrippingConfigSnapshotHolder.class);
 
     private final String configSnapshot;
     private final StripCapabilitiesResult stripCapabilitiesResult;
 
-    public CapabilityStrippingConfigSnapshotHolder(Element snapshot, Set<String> capabilities, Pattern ignoredMissingCapabilityRegex) {
+    public CapabilityStrippingConfigSnapshotHolder(Element snapshot, Set<String> capabilities) {
         final XmlElement configElement = XmlElement.fromDomElement(snapshot);
         configSnapshot = XmlUtil.toString(configElement.getDomElement());
-        stripCapabilitiesResult = stripCapabilities(configElement, capabilities, ignoredMissingCapabilityRegex);
+        stripCapabilitiesResult = stripCapabilities(configElement, capabilities);
     }
 
     private static class StripCapabilitiesResult {
-        private final SortedSet<String> requiredCapabilities, missingNamespaces;
+        private final SortedSet<String> requiredCapabilities, obsoleteCapabilities;
 
-        private StripCapabilitiesResult(SortedSet<String> requiredCapabilities, SortedSet<String> missingNamespaces) {
+        private StripCapabilitiesResult(SortedSet<String> requiredCapabilities, SortedSet<String> obsoleteCapabilities) {
             this.requiredCapabilities = Collections.unmodifiableSortedSet(requiredCapabilities);
-            this.missingNamespaces = Collections.unmodifiableSortedSet(missingNamespaces);
+            this.obsoleteCapabilities = Collections.unmodifiableSortedSet(obsoleteCapabilities);
         }
     }
 
 
     @VisibleForTesting
-    static StripCapabilitiesResult stripCapabilities(XmlElement configElement, Set<String> allCapabilitiesFromHello,
-                                                     Pattern ignoredMissingCapabilityRegex) {
+    static StripCapabilitiesResult stripCapabilities(XmlElement configElement, Set<String> allCapabilitiesFromHello) {
         // collect all namespaces
         Set<String> foundNamespacesInXML = getNamespaces(configElement);
         logger.trace("All capabilities {}\nFound namespaces in XML {}", allCapabilitiesFromHello, foundNamespacesInXML);
         // required are referenced both in xml and hello
         SortedSet<String> requiredCapabilities = new TreeSet<>();
         // can be removed
-        Set<String> obsoleteCapabilities = new HashSet<>();
-        // are in xml but not in hello
-        SortedSet<String> missingNamespaces = new TreeSet<>(foundNamespacesInXML);
+        SortedSet<String> obsoleteCapabilities = new TreeSet<>();
         for (String capability : allCapabilitiesFromHello) {
             String namespace = capability.replaceAll("\\?.*","");
             if (foundNamespacesInXML.contains(namespace)) {
                 requiredCapabilities.add(capability);
-                checkState(missingNamespaces.remove(namespace));
             } else {
                 obsoleteCapabilities.add(capability);
             }
@@ -74,17 +71,7 @@ public class CapabilityStrippingConfigSnapshotHolder implements ConfigSnapshotHo
         logger.trace("Required capabilities {}, \nObsolete capabilities {}",
                 requiredCapabilities, obsoleteCapabilities);
 
-        for(Iterator<String> iterator = missingNamespaces.iterator();iterator.hasNext(); ){
-            String capability = iterator.next();
-            if (ignoredMissingCapabilityRegex.matcher(capability).matches()){
-                logger.trace("Ignoring missing capability {}", capability);
-                iterator.remove();
-            }
-        }
-        if (missingNamespaces.size() > 0) {
-            logger.warn("Some capabilities are missing: {}", missingNamespaces);
-        }
-        return new StripCapabilitiesResult(requiredCapabilities, missingNamespaces);
+        return new StripCapabilitiesResult(requiredCapabilities, obsoleteCapabilities);
     }
 
     static Set<String> getNamespaces(XmlElement element){
@@ -94,7 +81,6 @@ public class CapabilityStrippingConfigSnapshotHolder implements ConfigSnapshotHo
                 result.add(attribute.getValue().getValue());
             }
         }
-        //element.getAttributes()
         for(XmlElement child: element.getChildElements()) {
             result.addAll(getNamespaces(child));
         }
@@ -107,8 +93,8 @@ public class CapabilityStrippingConfigSnapshotHolder implements ConfigSnapshotHo
     }
 
     @VisibleForTesting
-    Set<String> getMissingNamespaces(){
-        return stripCapabilitiesResult.missingNamespaces;
+    Set<String> getObsoleteCapabilities(){
+        return stripCapabilitiesResult.obsoleteCapabilities;
     }
 
     @Override
index 2d89bbc55c03d59d3ad7e648426df91562fc6fde..eb6fd2722a4cbdb9860ec4faf57462403ff02fbd 100644 (file)
@@ -23,7 +23,6 @@ import javax.management.NotificationListener;
 import javax.management.ObjectName;
 import java.io.Closeable;
 import java.io.IOException;
-import java.util.regex.Pattern;
 
 /**
  * Responsible for listening for notifications from netconf (via JMX) containing latest
@@ -39,9 +38,9 @@ public class ConfigPersisterNotificationHandler implements Closeable {
 
 
     public ConfigPersisterNotificationHandler(MBeanServerConnection mBeanServerConnection,
-                                              Persister persisterAggregator, Pattern ignoredMissingCapabilityRegex) {
+                                              Persister persisterAggregator) {
         this.mBeanServerConnection = mBeanServerConnection;
-        listener = new ConfigPersisterNotificationListener(persisterAggregator, ignoredMissingCapabilityRegex);
+        listener = new ConfigPersisterNotificationListener(persisterAggregator);
         registerAsJMXListener(mBeanServerConnection, listener);
 
     }
@@ -73,17 +72,16 @@ class ConfigPersisterNotificationListener implements NotificationListener {
     private static final Logger logger = LoggerFactory.getLogger(ConfigPersisterNotificationListener.class);
 
     private final Persister persisterAggregator;
-    private final Pattern ignoredMissingCapabilityRegex;
 
-    ConfigPersisterNotificationListener(Persister persisterAggregator, Pattern ignoredMissingCapabilityRegex) {
+    ConfigPersisterNotificationListener(Persister persisterAggregator) {
         this.persisterAggregator = persisterAggregator;
-        this.ignoredMissingCapabilityRegex = ignoredMissingCapabilityRegex;
     }
 
     @Override
     public void handleNotification(Notification notification, Object handback) {
-        if (notification instanceof NetconfJMXNotification == false)
+        if (notification instanceof NetconfJMXNotification == false) {
             return;
+        }
 
         // Socket should not be closed at this point
         // Activator unregisters this as JMX listener before close is called
@@ -98,14 +96,15 @@ class ConfigPersisterNotificationListener implements NotificationListener {
                 logger.warn("Exception occured during notification handling: ", e);
                 throw e;
             }
-        } else
+        } else {
             throw new IllegalStateException("Unknown config registry notification type " + notification);
+        }
     }
 
     private void handleAfterCommitNotification(final CommitJMXNotification notification) {
         try {
             persisterAggregator.persistConfig(new CapabilityStrippingConfigSnapshotHolder(notification.getConfigSnapshot(),
-                    notification.getCapabilities(), ignoredMissingCapabilityRegex));
+                    notification.getCapabilities()));
             logger.trace("Configuration persisted successfully");
         } catch (IOException e) {
             throw new RuntimeException("Unable to persist configuration snapshot", e);
index ea2a46dba535f825d0baa7b5dfa58d4b6371c297..6dba9ac64e22e1e5d5f528aa6b8c830aa78d9f17 100644 (file)
@@ -8,14 +8,21 @@
 
 package org.opendaylight.controller.netconf.persist.impl;
 
+import com.google.common.base.Function;
 import com.google.common.base.Preconditions;
+import com.google.common.base.Stopwatch;
+import com.google.common.collect.Collections2;
 import org.opendaylight.controller.config.api.ConflictingVersionException;
 import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
+import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
 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.mapping.api.Capability;
+import org.opendaylight.controller.netconf.mapping.api.HandlingPriority;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperation;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationChainedExecution;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactory;
 import org.opendaylight.controller.netconf.util.NetconfUtil;
-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;
@@ -28,38 +35,36 @@ import org.xml.sax.SAXException;
 import javax.annotation.concurrent.Immutable;
 import java.io.IOException;
 import java.io.InputStream;
-import java.util.Collections;
+import java.util.Collection;
 import java.util.HashSet;
 import java.util.LinkedHashMap;
 import java.util.List;
+import java.util.Map.Entry;
 import java.util.Set;
-import java.util.concurrent.ExecutionException;
+import java.util.TreeMap;
 import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
 
 @Immutable
 public class ConfigPusher {
     private static final Logger logger = LoggerFactory.getLogger(ConfigPusher.class);
 
-    private final ConfigPusherConfiguration configuration;
+    private final long maxWaitForCapabilitiesMillis;
+    private final long conflictingVersionTimeoutMillis;
+    private final NetconfOperationServiceFactory configNetconfConnector;
 
-    public ConfigPusher(ConfigPusherConfiguration configuration) {
-        this.configuration = configuration;
+    public ConfigPusher(NetconfOperationServiceFactory configNetconfConnector, long maxWaitForCapabilitiesMillis,
+                        long conflictingVersionTimeoutMillis) {
+        this.configNetconfConnector = configNetconfConnector;
+        this.maxWaitForCapabilitiesMillis = maxWaitForCapabilitiesMillis;
+        this.conflictingVersionTimeoutMillis = conflictingVersionTimeoutMillis;
     }
 
-    public synchronized LinkedHashMap<ConfigSnapshotHolder, EditAndCommitResponseWithRetries> pushConfigs(
-            List<ConfigSnapshotHolder> configs) throws InterruptedException {
+    public synchronized LinkedHashMap<ConfigSnapshotHolder, EditAndCommitResponse> pushConfigs(List<ConfigSnapshotHolder> configs) {
         logger.debug("Last config snapshots to be pushed to netconf: {}", configs);
-
-        // first just make sure we can connect to netconf, even if nothing is being pushed
-        {
-            NetconfClient netconfClient = makeNetconfConnection(Collections.<String>emptySet());
-            Util.closeClientAndDispatcher(netconfClient);
-        }
-        LinkedHashMap<ConfigSnapshotHolder, EditAndCommitResponseWithRetries> result = new LinkedHashMap<>();
+        LinkedHashMap<ConfigSnapshotHolder, EditAndCommitResponse> result = new LinkedHashMap<>();
         // start pushing snapshots:
         for (ConfigSnapshotHolder configSnapshotHolder : configs) {
-            EditAndCommitResponseWithRetries editAndCommitResponseWithRetries = pushSnapshotWithRetries(configSnapshotHolder);
+            EditAndCommitResponse editAndCommitResponseWithRetries = pushConfigWithConflictingVersionRetries(configSnapshotHolder);
             logger.debug("Config snapshot pushed successfully: {}, result: {}", configSnapshotHolder, result);
             result.put(configSnapshotHolder, editAndCommitResponseWithRetries);
         }
@@ -68,106 +73,101 @@ public class ConfigPusher {
     }
 
     /**
-     * Checks for ConflictingVersionException and retries until optimistic lock succeeds or maximal
-     * number of attempts is reached.
+     * First calls {@link #getOperationServiceWithRetries(java.util.Set, String)} in order to wait until
+     * expected capabilities are present, then tries to push configuration. If {@link ConflictingVersionException}
+     * is caught, whole process is retried - new service instance need to be obtained from the factory. Closes
+     * {@link NetconfOperationService} after each use.
      */
-    private synchronized EditAndCommitResponseWithRetries pushSnapshotWithRetries(ConfigSnapshotHolder configSnapshotHolder)
-            throws InterruptedException {
-
-        ConflictingVersionException lastException = null;
-        int maxAttempts = configuration.netconfPushConfigAttempts;
-
-        for (int retryAttempt = 1; retryAttempt <= maxAttempts; retryAttempt++) {
-            NetconfClient netconfClient = makeNetconfConnection(configSnapshotHolder.getCapabilities());
-            logger.trace("Pushing following xml to netconf {}", configSnapshotHolder);
-            try {
-                EditAndCommitResponse editAndCommitResponse = pushLastConfig(configSnapshotHolder, netconfClient);
-                return new EditAndCommitResponseWithRetries(editAndCommitResponse, retryAttempt);
+    private synchronized EditAndCommitResponse pushConfigWithConflictingVersionRetries(ConfigSnapshotHolder configSnapshotHolder) {
+        ConflictingVersionException lastException;
+        Stopwatch stopwatch = new Stopwatch().start();
+        do {
+            try (NetconfOperationService operationService = getOperationServiceWithRetries(configSnapshotHolder.getCapabilities(), configSnapshotHolder.toString())) {
+                return pushConfig(configSnapshotHolder, operationService);
             } catch (ConflictingVersionException e) {
-                logger.debug("Conflicting version detected, will retry after timeout");
                 lastException = e;
-                Thread.sleep(configuration.netconfPushConfigDelayMs);
-            } catch (RuntimeException e) {
-                throw new IllegalStateException("Unable to load " + configSnapshotHolder, e);
-            } finally {
-                Util.closeClientAndDispatcher(netconfClient);
+                logger.debug("Conflicting version detected, will retry after timeout");
+                sleep();
             }
-        }
-        throw new IllegalStateException("Maximum attempt count has been reached for pushing " + configSnapshotHolder,
+        } while (stopwatch.elapsed(TimeUnit.MILLISECONDS) < conflictingVersionTimeoutMillis);
+        throw new IllegalStateException("Max wait for conflicting version stabilization timeout after " + stopwatch.elapsed(TimeUnit.MILLISECONDS) + " ms",
                 lastException);
     }
 
-    /**
-     * @param expectedCaps capabilities that server hello must contain. Will retry until all are found or throws RuntimeException.
-     *                     If empty set is provided, will only make sure netconf client successfuly connected to the server.
-     * @return NetconfClient that has all required capabilities from server.
-     */
-    private synchronized NetconfClient makeNetconfConnection(Set<String> expectedCaps) throws InterruptedException {
-
-        // TODO think about moving capability subset check to netconf client
-        // could be utilized by integration tests
-
-        final long pollingStartNanos = System.nanoTime();
-        final long deadlineNanos = pollingStartNanos + TimeUnit.MILLISECONDS.toNanos(configuration.netconfCapabilitiesWaitTimeoutMs);
-        int attempt = 0;
-
-        NetconfHelloMessageAdditionalHeader additionalHeader = new NetconfHelloMessageAdditionalHeader("unknown",
-                configuration.netconfAddress.getAddress().getHostAddress(),
-                Integer.toString(configuration.netconfAddress.getPort()), "tcp", "persister");
-
-        Set<String> latestCapabilities = null;
-        while (System.nanoTime() < deadlineNanos) {
-            attempt++;
-            NetconfClientDispatcher netconfClientDispatcher = new NetconfClientDispatcher(configuration.eventLoopGroup,
-                    configuration.eventLoopGroup, additionalHeader, configuration.connectionAttemptTimeoutMs);
-            NetconfClient netconfClient;
+    private NetconfOperationService getOperationServiceWithRetries(Set<String> expectedCapabilities, String idForReporting) {
+        Stopwatch stopwatch = new Stopwatch().start();
+        NotEnoughCapabilitiesException lastException;
+        do {
             try {
-                netconfClient = new NetconfClient(this.toString(), configuration.netconfAddress, configuration.connectionAttemptDelayMs, netconfClientDispatcher);
-            } catch (IllegalStateException e) {
-                logger.debug("Netconf {} was not initialized or is not stable, attempt {}", configuration.netconfAddress, attempt, e);
-                netconfClientDispatcher.close();
-                Thread.sleep(configuration.connectionAttemptDelayMs);
-                continue;
-            }
-            latestCapabilities = netconfClient.getCapabilities();
-            if (Util.isSubset(netconfClient, expectedCaps)) {
-                logger.debug("Hello from netconf stable with {} capabilities", latestCapabilities);
-                logger.trace("Session id received from netconf server: {}", netconfClient.getClientSession());
-                return netconfClient;
+                return getOperationService(expectedCapabilities, idForReporting);
+            } catch (NotEnoughCapabilitiesException e) {
+                logger.debug("Not enough capabilities: " + e.toString());
+                lastException = e;
+                sleep();
             }
-            Set<String> allNotFound = computeNotFoundCapabilities(expectedCaps, latestCapabilities);
-            logger.debug("Netconf server did not provide required capabilities. Attempt {}. " +
-                    "Expected but not found: {}, all expected {}, current {}",
-                    attempt, allNotFound, expectedCaps, latestCapabilities);
-            Util.closeClientAndDispatcher(netconfClient);
-            Thread.sleep(configuration.connectionAttemptDelayMs);
+        } while (stopwatch.elapsed(TimeUnit.MILLISECONDS) < maxWaitForCapabilitiesMillis);
+        throw new IllegalStateException("Max wait for capabilities reached." + lastException.getMessage(), lastException);
+    }
+
+    private static class NotEnoughCapabilitiesException extends Exception {
+        private NotEnoughCapabilitiesException(String message) {
+            super(message);
         }
-        if (latestCapabilities == null) {
-            logger.error("Could not connect to the server in {} ms", configuration.netconfCapabilitiesWaitTimeoutMs);
-            throw new RuntimeException("Could not connect to netconf server");
+    }
+
+    /**
+     * Get NetconfOperationService iif all required capabilities are present.
+     *
+     * @param expectedCapabilities that must be provided by configNetconfConnector
+     * @param idForReporting
+     * @return service if capabilities are present, otherwise absent value
+     */
+    private NetconfOperationService getOperationService(Set<String> expectedCapabilities, String idForReporting) throws NotEnoughCapabilitiesException {
+        NetconfOperationService serviceCandidate = configNetconfConnector.createService(idForReporting);
+        Set<String> notFoundDiff = computeNotFoundCapabilities(expectedCapabilities, serviceCandidate);
+        if (notFoundDiff.isEmpty()) {
+            return serviceCandidate;
+        } else {
+            serviceCandidate.close();
+            logger.debug("Netconf server did not provide required capabilities for {} " +
+                            "Expected but not found: {}, all expected {}, current {}",
+                    idForReporting, notFoundDiff, expectedCapabilities, serviceCandidate.getCapabilities()
+            );
+            throw new NotEnoughCapabilitiesException("Not enough capabilities for " + idForReporting + ". Expected but not found: " + notFoundDiff);
         }
-        Set<String> allNotFound = computeNotFoundCapabilities(expectedCaps, latestCapabilities);
-        logger.error("Netconf server did not provide required capabilities. Expected but not found: {}, all expected {}, current {}",
-                allNotFound, expectedCaps, latestCapabilities);
-        throw new RuntimeException("Netconf server did not provide required capabilities. Expected but not found:" + allNotFound);
     }
 
-    private static Set<String> computeNotFoundCapabilities(Set<String> expectedCaps, Set<String> latestCapabilities) {
-        Set<String> allNotFound = new HashSet<>(expectedCaps);
-        allNotFound.removeAll(latestCapabilities);
+    private static Set<String> computeNotFoundCapabilities(Set<String> expectedCapabilities, NetconfOperationService serviceCandidate) {
+        Collection<String> actual = Collections2.transform(serviceCandidate.getCapabilities(), new Function<Capability, String>() {
+            @Override
+            public String apply(Capability input) {
+                return input.getCapabilityUri();
+            }
+        });
+        Set<String> allNotFound = new HashSet<>(expectedCapabilities);
+        allNotFound.removeAll(actual);
         return allNotFound;
     }
 
 
+
+    private void sleep() {
+        try {
+            Thread.sleep(100);
+        } catch (InterruptedException e) {
+            Thread.currentThread().interrupt();
+            throw new IllegalStateException(e);
+        }
+    }
+
     /**
      * Sends two RPCs to the netconf server: edit-config and commit.
      *
      * @param configSnapshotHolder
-     * @param netconfClient
      * @throws ConflictingVersionException if commit fails on optimistic lock failure inside of config-manager
      * @throws java.lang.RuntimeException  if edit-config or commit fails otherwise
      */
-    private synchronized EditAndCommitResponse pushLastConfig(ConfigSnapshotHolder configSnapshotHolder, NetconfClient netconfClient)
+    private synchronized EditAndCommitResponse pushConfig(ConfigSnapshotHolder configSnapshotHolder, NetconfOperationService operationService)
             throws ConflictingVersionException {
 
         Element xmlToBePersisted;
@@ -177,56 +177,66 @@ public class ConfigPusher {
             throw new IllegalStateException("Cannot parse " + configSnapshotHolder);
         }
         logger.trace("Pushing last configuration to netconf: {}", configSnapshotHolder);
-
+        Stopwatch stopwatch = new Stopwatch().start();
         NetconfMessage editConfigMessage = createEditConfigMessage(xmlToBePersisted);
 
-        // sending message to netconf
-        NetconfMessage editResponseMessage;
-        try {
-            editResponseMessage = sendRequestGetResponseCheckIsOK(editConfigMessage, netconfClient);
-        } catch (IOException e) {
-            throw new IllegalStateException("Edit-config failed on " + configSnapshotHolder, e);
-        }
+        Document editResponseMessage = sendRequestGetResponseCheckIsOK(editConfigMessage, operationService,
+                "edit-config", configSnapshotHolder.toString());
 
-        // commit
-        NetconfMessage commitResponseMessage;
-        try {
-            commitResponseMessage = sendRequestGetResponseCheckIsOK(getCommitMessage(), netconfClient);
-        } catch (IOException e) {
-            throw new IllegalStateException("Edit commit succeeded, but commit failed on " + configSnapshotHolder, e);
-        }
+        Document commitResponseMessage = sendRequestGetResponseCheckIsOK(getCommitMessage(), operationService,
+                "commit", configSnapshotHolder.toString());
 
         if (logger.isTraceEnabled()) {
             StringBuilder response = new StringBuilder("editConfig response = {");
-            response.append(XmlUtil.toString(editResponseMessage.getDocument()));
+            response.append(XmlUtil.toString(editResponseMessage));
             response.append("}");
             response.append("commit response = {");
-            response.append(XmlUtil.toString(commitResponseMessage.getDocument()));
+            response.append(XmlUtil.toString(commitResponseMessage));
             response.append("}");
             logger.trace("Last configuration loaded successfully");
             logger.trace("Detailed message {}", response);
+            logger.trace("Total time spent {} ms", stopwatch.elapsed(TimeUnit.MILLISECONDS));
         }
         return new EditAndCommitResponse(editResponseMessage, commitResponseMessage);
     }
 
+    private NetconfOperation findOperation(NetconfMessage request, NetconfOperationService operationService) {
+        TreeMap<HandlingPriority, NetconfOperation> allOperations = new TreeMap<>();
+        Set<NetconfOperation> netconfOperations = operationService.getNetconfOperations();
+        if (netconfOperations.isEmpty()) {
+            throw new IllegalStateException("Possible code error: no config operations");
+        }
+        for (NetconfOperation netconfOperation : netconfOperations) {
+            HandlingPriority handlingPriority = netconfOperation.canHandle(request.getDocument());
+            allOperations.put(handlingPriority, netconfOperation);
+        }
+        Entry<HandlingPriority, NetconfOperation> highestEntry = allOperations.lastEntry();
+        if (highestEntry.getKey().isCannotHandle()) {
+            throw new IllegalStateException("Possible code error: operation with highest priority is CANNOT_HANDLE");
+        }
+        return highestEntry.getValue();
+    }
+
+    private Document sendRequestGetResponseCheckIsOK(NetconfMessage request, NetconfOperationService operationService,
+                                                     String operationNameForReporting, String configIdForReporting)
+            throws ConflictingVersionException {
 
-    private NetconfMessage sendRequestGetResponseCheckIsOK(NetconfMessage request, NetconfClient netconfClient)
-            throws ConflictingVersionException, IOException {
+        NetconfOperation operation = findOperation(request, operationService);
+        Document response;
         try {
-            NetconfMessage netconfMessage = netconfClient.sendMessage(request,
-                    configuration.netconfSendMessageMaxAttempts, configuration.netconfSendMessageDelayMs);
-            NetconfUtil.checkIsMessageOk(netconfMessage);
-            return netconfMessage;
-        } catch(ConflictingVersionException e) {
-            logger.trace("conflicting version detected: {}", e.toString());
+            response = operation.handle(request.getDocument(), NetconfOperationChainedExecution.EXECUTION_TERMINATION_POINT);
+        } catch (NetconfDocumentedException | RuntimeException e) {
+            throw new IllegalStateException("Failed to send " + operationNameForReporting +
+                    " for configuration " + configIdForReporting, e);
+        }
+        try {
+            return NetconfUtil.checkIsMessageOk(response);
+        } catch (ConflictingVersionException e) {
+            logger.trace("conflicting version detected: {} while committing {}", e.toString(), configIdForReporting);
             throw e;
-        } catch (RuntimeException | ExecutionException | InterruptedException | TimeoutException e) { // TODO: change NetconfClient#sendMessage to throw checked exceptions
-            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";
@@ -246,7 +256,7 @@ public class ConfigPusher {
             return new NetconfMessage(doc);
         } catch (IOException | SAXException e) {
             // error reading the xml file bundled into the jar
-            throw new RuntimeException("Error while opening local resource " + editConfigResourcePath, e);
+            throw new IllegalStateException("Error while opening local resource " + editConfigResourcePath, e);
         }
     }
 
@@ -257,23 +267,23 @@ public class ConfigPusher {
             return new NetconfMessage(XmlUtil.readXmlToDocument(stream));
         } catch (SAXException | IOException e) {
             // error reading the xml file bundled into the jar
-            throw new RuntimeException("Error while opening local resource " + resource, e);
+            throw new IllegalStateException("Error while opening local resource " + resource, e);
         }
     }
 
     static class EditAndCommitResponse {
-        private final NetconfMessage editResponse, commitResponse;
+        private final Document editResponse, commitResponse;
 
-        EditAndCommitResponse(NetconfMessage editResponse, NetconfMessage commitResponse) {
+        EditAndCommitResponse(Document editResponse, Document commitResponse) {
             this.editResponse = editResponse;
             this.commitResponse = commitResponse;
         }
 
-        public NetconfMessage getEditResponse() {
+        public Document getEditResponse() {
             return editResponse;
         }
 
-        public NetconfMessage getCommitResponse() {
+        public Document getCommitResponse() {
             return commitResponse;
         }
 
@@ -285,32 +295,4 @@ public class ConfigPusher {
                     '}';
         }
     }
-
-
-    static class EditAndCommitResponseWithRetries {
-        private final EditAndCommitResponse editAndCommitResponse;
-        private final int retries;
-
-        EditAndCommitResponseWithRetries(EditAndCommitResponse editAndCommitResponse, int retries) {
-            this.editAndCommitResponse = editAndCommitResponse;
-            this.retries = retries;
-        }
-
-        public int getRetries() {
-            return retries;
-        }
-
-        public EditAndCommitResponse getEditAndCommitResponse() {
-            return editAndCommitResponse;
-        }
-
-        @Override
-        public String toString() {
-            return "EditAndCommitResponseWithRetries{" +
-                    "editAndCommitResponse=" + editAndCommitResponse +
-                    ", retries=" + retries +
-                    '}';
-        }
-    }
-
 }
diff --git a/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/ConfigPusherConfiguration.java b/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/ConfigPusherConfiguration.java
deleted file mode 100644 (file)
index aa189f0..0000000
+++ /dev/null
@@ -1,83 +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.persist.impl;
-
-import io.netty.channel.EventLoopGroup;
-
-import javax.annotation.concurrent.Immutable;
-import java.net.InetSocketAddress;
-import java.util.concurrent.TimeUnit;
-
-/**
- * Configuration properties for ConfigPusher. Contains delays and timeouts for netconf
- * connection establishment, netconf capabilities stabilization and configuration push.
- */
-@Immutable
-public final class ConfigPusherConfiguration {
-
-    public static final long DEFAULT_CONNECTION_ATTEMPT_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(5);
-    public static final int DEFAULT_CONNECTION_ATTEMPT_DELAY_MS = 5000;
-
-    public static final int DEFAULT_NETCONF_SEND_MESSAGE_MAX_ATTEMPTS = 20;
-    public static final int DEFAULT_NETCONF_SEND_MESSAGE_DELAY_MS = 1000;
-
-    public static final long DEFAULT_NETCONF_CAPABILITIES_WAIT_TIMEOUT_MS = TimeUnit.MINUTES.toMillis(2);
-
-    public static final int DEFAULT_NETCONF_PUSH_CONFIG_ATTEMPTS = 30;
-    public static final long DEFAULT_NETCONF_PUSH_CONFIG_DELAY_MS = TimeUnit.MINUTES.toMillis(1);
-
-    final InetSocketAddress netconfAddress;
-    final EventLoopGroup eventLoopGroup;
-
-    /**
-     * Total time to wait for capability stabilization
-     */
-    final long netconfCapabilitiesWaitTimeoutMs;
-
-    /**
-     * Delay between message send attempts
-     */
-    final int netconfSendMessageDelayMs;
-    /**
-     * Total number attempts to send a message
-     */
-    final int netconfSendMessageMaxAttempts;
-
-    /**
-     * Delay between connection establishment attempts
-     */
-    final int connectionAttemptDelayMs;
-    /**
-     * Total number of attempts to perform connection establishment
-     */
-    final long connectionAttemptTimeoutMs;
-
-    /**
-     * Total number of attempts to push configuration to netconf
-     */
-    final int netconfPushConfigAttempts;
-    /**
-     * Delay between configuration push attempts
-     */
-    final long netconfPushConfigDelayMs;
-
-    ConfigPusherConfiguration(InetSocketAddress netconfAddress, long netconfCapabilitiesWaitTimeoutMs,
-            int netconfSendMessageDelayMs, int netconfSendMessageMaxAttempts, int connectionAttemptDelayMs,
-            long connectionAttemptTimeoutMs, EventLoopGroup eventLoopGroup, int netconfPushConfigAttempts,
-            long netconfPushConfigDelayMs) {
-        this.netconfAddress = netconfAddress;
-        this.netconfCapabilitiesWaitTimeoutMs = netconfCapabilitiesWaitTimeoutMs;
-        this.netconfSendMessageDelayMs = netconfSendMessageDelayMs;
-        this.netconfSendMessageMaxAttempts = netconfSendMessageMaxAttempts;
-        this.connectionAttemptDelayMs = connectionAttemptDelayMs;
-        this.connectionAttemptTimeoutMs = connectionAttemptTimeoutMs;
-        this.eventLoopGroup = eventLoopGroup;
-        this.netconfPushConfigAttempts = netconfPushConfigAttempts;
-        this.netconfPushConfigDelayMs = netconfPushConfigDelayMs;
-    }
-}
diff --git a/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/ConfigPusherConfigurationBuilder.java b/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/ConfigPusherConfigurationBuilder.java
deleted file mode 100644 (file)
index c26dc8d..0000000
+++ /dev/null
@@ -1,85 +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.persist.impl;
-
-import io.netty.channel.EventLoopGroup;
-
-import java.net.InetSocketAddress;
-
-public class ConfigPusherConfigurationBuilder {
-    InetSocketAddress netconfAddress;
-    EventLoopGroup eventLoopGroup;
-
-    long netconfCapabilitiesWaitTimeoutMs = ConfigPusherConfiguration.DEFAULT_NETCONF_CAPABILITIES_WAIT_TIMEOUT_MS;
-    int netconfSendMessageDelayMs = ConfigPusherConfiguration.DEFAULT_NETCONF_SEND_MESSAGE_DELAY_MS;
-    int netconfSendMessageMaxAttempts = ConfigPusherConfiguration.DEFAULT_NETCONF_SEND_MESSAGE_MAX_ATTEMPTS;
-    int connectionAttemptDelayMs = ConfigPusherConfiguration.DEFAULT_CONNECTION_ATTEMPT_DELAY_MS;
-    long connectionAttemptTimeoutMs = ConfigPusherConfiguration.DEFAULT_CONNECTION_ATTEMPT_TIMEOUT_MS;
-    int netconfPushConfigAttempts = ConfigPusherConfiguration.DEFAULT_NETCONF_PUSH_CONFIG_ATTEMPTS;
-    long netconfPushConfigDelayMs = ConfigPusherConfiguration.DEFAULT_NETCONF_PUSH_CONFIG_DELAY_MS;
-
-    private ConfigPusherConfigurationBuilder() {
-    }
-
-    public static ConfigPusherConfigurationBuilder aConfigPusherConfiguration() {
-        return new ConfigPusherConfigurationBuilder();
-    }
-
-    public ConfigPusherConfigurationBuilder withNetconfAddress(InetSocketAddress netconfAddress) {
-        this.netconfAddress = netconfAddress;
-        return this;
-    }
-
-    public ConfigPusherConfigurationBuilder withNetconfCapabilitiesWaitTimeoutMs(long netconfCapabilitiesWaitTimeoutMs) {
-        this.netconfCapabilitiesWaitTimeoutMs = netconfCapabilitiesWaitTimeoutMs;
-        return this;
-    }
-
-    public ConfigPusherConfigurationBuilder withNetconfSendMessageDelayMs(int netconfSendMessageDelayMs) {
-        this.netconfSendMessageDelayMs = netconfSendMessageDelayMs;
-        return this;
-    }
-
-    public ConfigPusherConfigurationBuilder withNetconfSendMessageMaxAttempts(int netconfSendMessageMaxAttempts) {
-        this.netconfSendMessageMaxAttempts = netconfSendMessageMaxAttempts;
-        return this;
-    }
-
-    public ConfigPusherConfigurationBuilder withConnectionAttemptDelayMs(int connectionAttemptDelayMs) {
-        this.connectionAttemptDelayMs = connectionAttemptDelayMs;
-        return this;
-    }
-
-    public ConfigPusherConfigurationBuilder withConnectionAttemptTimeoutMs(long connectionAttemptTimeoutMs) {
-        this.connectionAttemptTimeoutMs = connectionAttemptTimeoutMs;
-        return this;
-    }
-
-    public ConfigPusherConfigurationBuilder withEventLoopGroup(EventLoopGroup eventLoopGroup) {
-        this.eventLoopGroup = eventLoopGroup;
-        return this;
-    }
-
-    public ConfigPusherConfigurationBuilder withNetconfPushConfigAttempts(int netconfPushConfigAttempts) {
-        this.netconfPushConfigAttempts = netconfPushConfigAttempts;
-        return this;
-    }
-
-    public ConfigPusherConfigurationBuilder withNetconfPushConfigDelayMs(long netconfPushConfigDelayMs) {
-        this.netconfPushConfigDelayMs = netconfPushConfigDelayMs;
-        return this;
-    }
-
-    public ConfigPusherConfiguration build() {
-        ConfigPusherConfiguration configPusherConfiguration = new ConfigPusherConfiguration(netconfAddress,
-                netconfCapabilitiesWaitTimeoutMs, netconfSendMessageDelayMs, netconfSendMessageMaxAttempts,
-                connectionAttemptDelayMs, connectionAttemptTimeoutMs, eventLoopGroup, netconfPushConfigAttempts,
-                netconfPushConfigDelayMs);
-        return configPusherConfiguration;
-    }
-}
diff --git a/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/Util.java b/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/Util.java
deleted file mode 100644 (file)
index 322a9b7..0000000
+++ /dev/null
@@ -1,53 +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.persist.impl;
-
-import org.opendaylight.controller.netconf.client.NetconfClient;
-import org.opendaylight.controller.netconf.client.NetconfClientDispatcher;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.util.Set;
-
-public final class Util {
-    private static final Logger logger = LoggerFactory.getLogger(Util.class);
-
-
-    public static boolean isSubset(NetconfClient netconfClient, Set<String> expectedCaps) {
-        return isSubset(netconfClient.getCapabilities(), expectedCaps);
-
-    }
-
-    private static boolean isSubset(Set<String> currentCapabilities, Set<String> expectedCaps) {
-        for (String exCap : expectedCaps) {
-            if (currentCapabilities.contains(exCap) == false)
-                return false;
-        }
-        return true;
-    }
-
-    public static void closeClientAndDispatcher(NetconfClient client) {
-        NetconfClientDispatcher dispatcher = client.getNetconfClientDispatcher();
-        Exception fromClient = null;
-        try {
-            client.close();
-        } catch (Exception e) {
-            fromClient = e;
-        } finally {
-            try {
-                dispatcher.close();
-            } catch (Exception e) {
-                if (fromClient != null) {
-                    e.addSuppressed(fromClient);
-                }
-                throw new RuntimeException("Error closing temporary client ", e);
-            }
-        }
-    }
-}
index 1246c78fbe21539589a23d641e58f4a1846da5c8..76afe8eb39b95f4500fd847cfe5df9a297c656e7 100644 (file)
 package org.opendaylight.controller.netconf.persist.impl.osgi;
 
 import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Optional;
-import io.netty.channel.EventLoopGroup;
-import io.netty.channel.nio.NioEventLoopGroup;
+import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactory;
 import org.opendaylight.controller.netconf.persist.impl.ConfigPersisterNotificationHandler;
 import org.opendaylight.controller.netconf.persist.impl.ConfigPusher;
-import org.opendaylight.controller.netconf.persist.impl.ConfigPusherConfiguration;
-import org.opendaylight.controller.netconf.persist.impl.ConfigPusherConfigurationBuilder;
 import org.opendaylight.controller.netconf.persist.impl.PersisterAggregator;
-import org.opendaylight.controller.netconf.util.osgi.NetconfConfigUtil;
 import org.osgi.framework.BundleActivator;
 import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.Filter;
+import org.osgi.framework.ServiceReference;
+import org.osgi.util.tracker.ServiceTracker;
+import org.osgi.util.tracker.ServiceTrackerCustomizer;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import javax.management.MBeanServer;
 import java.lang.management.ManagementFactory;
-import java.net.InetSocketAddress;
-import java.util.concurrent.ThreadFactory;
-import java.util.regex.Pattern;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
 
 public class ConfigPersisterActivator implements BundleActivator {
 
     private static final Logger logger = LoggerFactory.getLogger(ConfigPersisterActivator.class);
 
-    public static final String IGNORED_MISSING_CAPABILITY_REGEX_SUFFIX = "ignoredMissingCapabilityRegex";
-
-    public static final String MAX_WAIT_FOR_CAPABILITIES_MILLIS = "maxWaitForCapabilitiesMillis";
+    public static final String MAX_WAIT_FOR_CAPABILITIES_MILLIS_PROPERTY = "maxWaitForCapabilitiesMillis";
+    private static final long MAX_WAIT_FOR_CAPABILITIES_MILLIS_DEFAULT = TimeUnit.MINUTES.toMillis(2);
+    public static final String CONFLICTING_VERSION_TIMEOUT_MILLIS_PROPERTY = "conflictingVersionTimeoutMillis";
+    private static final long CONFLICTING_VERSION_TIMEOUT_MILLIS_DEFAULT = TimeUnit.SECONDS.toMillis(30);
 
     public static final String NETCONF_CONFIG_PERSISTER = "netconf.config.persister";
 
     public static final String STORAGE_ADAPTER_CLASS_PROP_SUFFIX = "storageAdapterClass";
 
-    public static final String DEFAULT_IGNORED_REGEX = "^urn:ietf:params:xml:ns:netconf:base:1.0";
 
-    private final MBeanServer platformMBeanServer;
+    private static final MBeanServer platformMBeanServer = ManagementFactory.getPlatformMBeanServer();
 
-    private final Optional<ConfigPusherConfiguration> initialConfigForPusher;
-    private volatile ConfigPersisterNotificationHandler jmxNotificationHandler;
-    private Thread initializationThread;
-    private ThreadFactory initializationThreadFactory;
-    private EventLoopGroup nettyThreadGroup;
-    private PersisterAggregator persisterAggregator;
+    private List<AutoCloseable> autoCloseables;
 
-    public ConfigPersisterActivator() {
-        this(new ThreadFactory() {
-            @Override
-            public Thread newThread(Runnable initializationRunnable) {
-                return new Thread(initializationRunnable, "ConfigPersister-registrator");
-            }
-        }, ManagementFactory.getPlatformMBeanServer(), null);
-    }
-
-    @VisibleForTesting
-    protected ConfigPersisterActivator(ThreadFactory threadFactory, MBeanServer mBeanServer,
-            ConfigPusherConfiguration initialConfigForPusher) {
-        this.initializationThreadFactory = threadFactory;
-        this.platformMBeanServer = mBeanServer;
-        this.initialConfigForPusher = Optional.fromNullable(initialConfigForPusher);
-    }
 
     @Override
     public void start(final BundleContext context) throws Exception {
         logger.debug("ConfigPersister starting");
-
+        autoCloseables = new ArrayList<>();
         PropertiesProviderBaseImpl propertiesProvider = new PropertiesProviderBaseImpl(context);
 
-        final Pattern ignoredMissingCapabilityRegex = getIgnoredCapabilitiesProperty(propertiesProvider);
 
-        persisterAggregator = PersisterAggregator.createFromProperties(propertiesProvider);
+        final PersisterAggregator persisterAggregator = PersisterAggregator.createFromProperties(propertiesProvider);
+        autoCloseables.add(persisterAggregator);
+        final long maxWaitForCapabilitiesMillis = getMaxWaitForCapabilitiesMillis(propertiesProvider);
+        final List<ConfigSnapshotHolder> configs = persisterAggregator.loadLastConfigs();
+        final long conflictingVersionTimeoutMillis = getConflictingVersionTimeoutMillis(propertiesProvider);
+        logger.trace("Following configs will be pushed: {}", configs);
+        ServiceTrackerCustomizer<NetconfOperationServiceFactory, NetconfOperationServiceFactory> configNetconfCustomizer = new ServiceTrackerCustomizer<NetconfOperationServiceFactory, NetconfOperationServiceFactory>() {
+            @Override
+            public NetconfOperationServiceFactory addingService(ServiceReference<NetconfOperationServiceFactory> reference) {
+                NetconfOperationServiceFactory service = reference.getBundle().getBundleContext().getService(reference);
+                final ConfigPusher configPusher = new ConfigPusher(service, maxWaitForCapabilitiesMillis, conflictingVersionTimeoutMillis);
+                logger.debug("Configuration Persister got %s", service);
+                final Thread pushingThread = new Thread(new Runnable() {
+                    @Override
+                    public void run() {
+                        configPusher.pushConfigs(configs);
+                        logger.info("Configuration Persister initialization completed.");
+                        ConfigPersisterNotificationHandler jmxNotificationHandler = new ConfigPersisterNotificationHandler(platformMBeanServer, persisterAggregator);
+                        synchronized (ConfigPersisterActivator.this) {
+                            autoCloseables.add(jmxNotificationHandler);
+                        }
+                    }
+                }, "config-pusher");
+                synchronized (ConfigPersisterActivator.this){
+                    autoCloseables.add(new AutoCloseable() {
+                        @Override
+                        public void close() throws Exception {
+                            pushingThread.interrupt();
+                        }
+                    });
+                }
+                pushingThread.start();
+                return service;
+            }
 
-        final ConfigPusher configPusher = new ConfigPusher(getConfigurationForPusher(context, propertiesProvider));
+            @Override
+            public void modifiedService(ServiceReference<NetconfOperationServiceFactory> reference, NetconfOperationServiceFactory service) {
+            }
 
-        // offload initialization to another thread in order to stop blocking activator
-        Runnable initializationRunnable = new Runnable() {
             @Override
-            public void run() {
-                try {
-                    configPusher.pushConfigs(persisterAggregator.loadLastConfigs());
-                    jmxNotificationHandler = new ConfigPersisterNotificationHandler(platformMBeanServer, persisterAggregator,
-                            ignoredMissingCapabilityRegex);
-                } catch (InterruptedException e) {
-                    Thread.currentThread().interrupt();
-                    logger.error("Interrupted while waiting for netconf connection");
-                    // uncaught exception handler will deal with this failure
-                    throw new RuntimeException("Interrupted while waiting for netconf connection", e);
-                }
-                logger.info("Configuration Persister initialization completed.");
+            public void removedService(ServiceReference<NetconfOperationServiceFactory> reference, NetconfOperationServiceFactory service) {
             }
         };
 
-        initializationThread = initializationThreadFactory.newThread(initializationRunnable);
-        initializationThread.start();
-    }
-
-    private Pattern getIgnoredCapabilitiesProperty(PropertiesProviderBaseImpl propertiesProvider) {
-        String regexProperty = propertiesProvider.getProperty(IGNORED_MISSING_CAPABILITY_REGEX_SUFFIX);
-        String regex;
-        if (regexProperty != null) {
-            regex = regexProperty;
-        } else {
-            regex = DEFAULT_IGNORED_REGEX;
-        }
-        return Pattern.compile(regex);
-    }
+        Filter filter = context.createFilter(getFilterString());
 
-    private Optional<Long> getMaxWaitForCapabilitiesProperty(PropertiesProviderBaseImpl propertiesProvider) {
-        String timeoutProperty = propertiesProvider.getProperty(MAX_WAIT_FOR_CAPABILITIES_MILLIS);
-        return Optional.fromNullable(timeoutProperty == null ? null : Long.valueOf(timeoutProperty));
+        ServiceTracker<NetconfOperationServiceFactory, NetconfOperationServiceFactory> tracker =
+                new ServiceTracker<>(context, filter, configNetconfCustomizer);
+        tracker.open();
     }
 
-    private ConfigPusherConfiguration getConfigurationForPusher(BundleContext context,
-            PropertiesProviderBaseImpl propertiesProvider) {
-
-        // If configuration was injected via constructor, use it
-        if(initialConfigForPusher.isPresent())
-            return initialConfigForPusher.get();
-
-        Optional<Long> maxWaitForCapabilitiesMillis = getMaxWaitForCapabilitiesProperty(propertiesProvider);
-        final InetSocketAddress address = NetconfConfigUtil.extractTCPNetconfAddress(context,
-                "Netconf is not configured, persister is not operational", true);
-
-        nettyThreadGroup = new NioEventLoopGroup();
 
-        ConfigPusherConfigurationBuilder configPusherConfigurationBuilder = ConfigPusherConfigurationBuilder.aConfigPusherConfiguration();
+    @VisibleForTesting
+    public static String getFilterString() {
+        return "(&" +
+                "(" + Constants.OBJECTCLASS + "=" + NetconfOperationServiceFactory.class.getName() + ")" +
+                "(name" + "=" + "config-netconf-connector" + ")" +
+                ")";
+    }
 
-        if(maxWaitForCapabilitiesMillis.isPresent())
-            configPusherConfigurationBuilder.withNetconfCapabilitiesWaitTimeoutMs(maxWaitForCapabilitiesMillis.get());
+    private long getConflictingVersionTimeoutMillis(PropertiesProviderBaseImpl propertiesProvider) {
+        String timeoutProperty = propertiesProvider.getProperty(CONFLICTING_VERSION_TIMEOUT_MILLIS_PROPERTY);
+        return timeoutProperty == null ? CONFLICTING_VERSION_TIMEOUT_MILLIS_DEFAULT : Long.valueOf(timeoutProperty);
+    }
 
-        return configPusherConfigurationBuilder
-                .withEventLoopGroup(nettyThreadGroup)
-                .withNetconfAddress(address)
-                .build();
+    private long getMaxWaitForCapabilitiesMillis(PropertiesProviderBaseImpl propertiesProvider) {
+        String timeoutProperty = propertiesProvider.getProperty(MAX_WAIT_FOR_CAPABILITIES_MILLIS_PROPERTY);
+        return timeoutProperty == null ? MAX_WAIT_FOR_CAPABILITIES_MILLIS_DEFAULT : Long.valueOf(timeoutProperty);
     }
 
     @Override
-    public void stop(BundleContext context) throws Exception {
-        initializationThread.interrupt();
-        if (jmxNotificationHandler != null) {
-            jmxNotificationHandler.close();
+    public synchronized void stop(BundleContext context) throws Exception {
+        Exception lastException = null;
+        for (AutoCloseable autoCloseable : autoCloseables) {
+            try {
+                autoCloseable.close();
+            } catch (Exception e) {
+                if (lastException == null) {
+                    lastException = e;
+                } else {
+                    lastException.addSuppressed(e);
+                }
+            }
+        }
+        if (lastException != null) {
+            throw lastException;
         }
-        if(nettyThreadGroup!=null)
-            nettyThreadGroup.shutdownGracefully();
-        persisterAggregator.close();
     }
 }
index d91712f3475fe2dde61692368a85e813b67c048c..7e9d80abc0a8814f655fdf964c946f98fe956058 100644 (file)
@@ -10,44 +10,30 @@ package org.opendaylight.controller.netconf.persist.impl;
 import com.google.common.collect.Sets;
 import org.apache.commons.io.IOUtils;
 import org.junit.Test;
-import org.opendaylight.controller.netconf.persist.impl.osgi.ConfigPersisterActivator;
 import org.opendaylight.controller.netconf.util.xml.XmlUtil;
 import org.w3c.dom.Element;
 
 import java.io.IOException;
-import java.util.Collections;
 import java.util.HashSet;
 import java.util.Set;
-import java.util.regex.Pattern;
 
 import static org.junit.Assert.assertEquals;
 
 public class CapabilityStrippingConfigSnapshotHolderTest {
 
     @Test
-    public void  testCapabilityStripping() throws Exception {
+    public void testCapabilityStripping() throws Exception {
         Set<String> allCapabilities = readLines("/capabilities-all.txt");
         Set<String> expectedCapabilities = readLines("/capabilities-stripped.txt");
         String snapshotAsString = readToString("/snapshot.xml");
         Element element = XmlUtil.readXmlToElement(snapshotAsString);
-        {
-            CapabilityStrippingConfigSnapshotHolder tested = new CapabilityStrippingConfigSnapshotHolder(
-                    element, allCapabilities, Pattern.compile(
-                    ConfigPersisterActivator.DEFAULT_IGNORED_REGEX
-            ));
-            assertEquals(expectedCapabilities, tested.getCapabilities());
-            assertEquals(Collections.emptySet(), tested.getMissingNamespaces());
-        }
-        {
-            // test regex
-            CapabilityStrippingConfigSnapshotHolder tested = new CapabilityStrippingConfigSnapshotHolder(
-                    element, allCapabilities, Pattern.compile(
-                    "^bar"
-            ));
-            assertEquals(expectedCapabilities, tested.getCapabilities());
-            assertEquals(Sets.newHashSet(ConfigPersisterActivator.DEFAULT_IGNORED_REGEX.substring(1)),
-                    tested.getMissingNamespaces());
-        }
+        CapabilityStrippingConfigSnapshotHolder tested = new CapabilityStrippingConfigSnapshotHolder(
+                element, allCapabilities);
+        assertEquals(expectedCapabilities, tested.getCapabilities());
+
+        Set<String> obsoleteCapabilities = Sets.difference(allCapabilities, expectedCapabilities);
+
+        assertEquals(obsoleteCapabilities, tested.getObsoleteCapabilities());
     }
 
     private Set<String> readLines(String fileName) throws IOException {
index 230c74725d0b3c78160bcfecf8c60b29eb42ccff..b722496142e4f2014b82e776317488e02ddb4527 100644 (file)
  */
 package org.opendaylight.controller.netconf.persist.impl.osgi;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertThat;
-
-import java.lang.management.ManagementFactory;
-import java.net.InetSocketAddress;
-import java.util.Collections;
-import java.util.List;
-import java.util.concurrent.ThreadFactory;
-import java.util.concurrent.TimeoutException;
-
-import javax.management.MBeanServer;
-
+import com.google.common.collect.Sets;
 import org.junit.After;
-import org.junit.AfterClass;
-import org.junit.BeforeClass;
+import org.junit.Before;
 import org.junit.Test;
-import org.junit.matchers.JUnitMatchers;
 import org.opendaylight.controller.config.api.ConflictingVersionException;
-import org.opendaylight.controller.netconf.impl.DefaultCommitNotificationProducer;
-import org.opendaylight.controller.netconf.persist.impl.ConfigPusherConfiguration;
-import org.opendaylight.controller.netconf.persist.impl.ConfigPusherConfigurationBuilder;
+import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.netconf.mapping.api.Capability;
+import org.opendaylight.controller.netconf.mapping.api.HandlingPriority;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperation;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationChainedExecution;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService;
+import org.opendaylight.controller.netconf.persist.impl.osgi.MockedBundleContext.DummyAdapterWithInitialSnapshot;
+import org.opendaylight.controller.netconf.util.xml.XmlUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+import org.xml.sax.SAXException;
 
-import com.google.common.collect.Lists;
-import io.netty.channel.nio.NioEventLoopGroup;
+import javax.management.MBeanServer;
+import java.io.IOException;
+import java.lang.management.ManagementFactory;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
 
 public class ConfigPersisterTest {
+    private static final Logger logger = LoggerFactory.getLogger(ConfigPersisterTest.class);
 
     private MockedBundleContext ctx;
     private ConfigPersisterActivator configPersisterActivator;
     private static final MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
+    private TestingExceptionHandler handler;
 
-    private static final String NETCONF_ADDRESS = "localhost";
-    private static final String NETCONF_PORT = "18383";
-    private static NioEventLoopGroup eventLoopGroup;
 
-    private void setUpContextAndStartPersister(Thread.UncaughtExceptionHandler exHandler, String requiredCapability, ConfigPusherConfiguration configuration)
-            throws Exception {
-        MockedBundleContext.DummyAdapterWithInitialSnapshot.expectedCapability = requiredCapability;
-        ctx = new MockedBundleContext(NETCONF_ADDRESS, NETCONF_PORT);
-        configPersisterActivator = new ConfigPersisterActivator(getThreadFactory(exHandler), mBeanServer,
-                configuration);
+    private void setUpContextAndStartPersister(String requiredCapability) throws Exception {
+        DummyAdapterWithInitialSnapshot.expectedCapability = requiredCapability;
+        ctx = new MockedBundleContext(1000, 1000);
+        configPersisterActivator = new ConfigPersisterActivator();
         configPersisterActivator.start(ctx.getBundleContext());
     }
 
-    @BeforeClass
-    public static void setUp() throws Exception {
-        eventLoopGroup = new NioEventLoopGroup();
+    @Before
+    public void setUp() {
+        handler = new TestingExceptionHandler();
+        Thread.setDefaultUncaughtExceptionHandler(handler);
     }
 
     @After
     public void tearDown() throws Exception {
+        Thread.setDefaultUncaughtExceptionHandler(null);
         configPersisterActivator.stop(ctx.getBundleContext());
     }
 
-    @AfterClass
-    public static void closeNettyGroup() throws Exception {
-        eventLoopGroup.shutdownGracefully();
-    }
-
-    @Test
-    public void testPersisterNetconfNotStarting() throws Exception {
-        final TestingExceptionHandler handler = new TestingExceptionHandler();
-
-        setUpContextAndStartPersister(handler, "cap2", getConfiguration(100, 100).build());
-
-        waitTestToFinish(2000);
-
-        handler.assertException("connect to netconf endpoint", RuntimeException.class,
-                "Could not connect to netconf server");
-    }
-
     @Test
     public void testPersisterNotAllCapabilitiesProvided() throws Exception {
-        final TestingExceptionHandler handler = new TestingExceptionHandler();
-        ConfigPusherConfiguration cfg = getConfiguration(500, 1000)
-                .withNetconfCapabilitiesWaitTimeoutMs(1000).build();
-
-        setUpContextAndStartPersister(handler, "required-cap", cfg);
+        setUpContextAndStartPersister("required-cap");
+        Thread.sleep(2000);
+        handler.assertException(IllegalStateException.class, "Max wait for capabilities reached.Not enough capabilities " +
+                "for <data><config-snapshot/></data>. Expected but not found: [required-cap]");
 
-        try (MockNetconfEndpoint endpoint = startMockNetconfEndpoint("cap1")) {
-
-            waitTestToFinish(2500);
-
-            handler.assertException("retrieve required capabilities from netconf endpoint", RuntimeException.class,
-                    "Expected but not found:[required-cap]");
-        }
     }
 
     @Test
-    public void testPersisterNoResponseFromNetconfAfterEdit() throws Exception {
-        final TestingExceptionHandler handler = new TestingExceptionHandler();
-        ConfigPusherConfiguration cfg = getConfigurationWithOnePushAttempt();
-
-        setUpContextAndStartPersister(handler, "cap1", cfg);
-
-        try (MockNetconfEndpoint endpoint = startMockNetconfEndpoint("cap1")) {
-
-            waitTestToFinish(3000);
-
-            handler.assertException("receive response from netconf endpoint", IllegalStateException.class,
-                    "Unable to load", TimeoutException.class,
-                    null, 3);
-
-            assertEquals(1 + 2, endpoint.getReceivedMessages().size());
-            assertHelloMessage(endpoint.getReceivedMessages().get(1));
-            assertEditMessage(endpoint.getReceivedMessages().get(2));
-        }
+    public void testPersisterSuccessfulPush() throws Exception {
+        setUpContextAndStartPersister("cap1");
+        NetconfOperationService service = getWorkingService(getOKDocument());
+        doReturn(service).when(ctx.serviceFactory).createService(anyString());
+        Thread.sleep(2000);
+        assertCannotRegisterAsJMXListener_pushWasSuccessful();
     }
 
-    private ConfigPusherConfiguration getConfigurationWithOnePushAttempt() {
-        return getConfiguration(500, 1000)
-                    .withNetconfCapabilitiesWaitTimeoutMs(1000)
-                    .withNetconfPushConfigAttempts(1)
-                    .withNetconfPushConfigDelayMs(100)
-                    .withNetconfSendMessageMaxAttempts(3)
-                    .withNetconfSendMessageDelayMs(500).build();
+    // this means pushing of config was successful
+    public void assertCannotRegisterAsJMXListener_pushWasSuccessful() {
+        handler.assertException(RuntimeException.class, "Cannot register as JMX listener to netconf");
     }
 
-    @Test
-    public void testPersisterSuccessfulPush() throws Exception {
-        final TestingExceptionHandler handler = new TestingExceptionHandler();
-        ConfigPusherConfiguration cfg = getConfigurationForSuccess();
-
-        setUpContextAndStartPersister(handler, "cap1", cfg);
-
-        try (MockNetconfEndpoint endpoint = startMockNetconfEndpoint("cap1", MockNetconfEndpoint.okMessage,
-                MockNetconfEndpoint.okMessage)) {
+    public NetconfOperationService getWorkingService(Document document) throws SAXException, IOException, NetconfDocumentedException {
+        NetconfOperationService service = mock(NetconfOperationService.class);
+        Capability capability = mock(Capability.class);
+        doReturn(Sets.newHashSet(capability)).when(service).getCapabilities();
+        doReturn("cap1").when(capability).getCapabilityUri();
 
-            waitTestToFinish(4000);
 
-            handler.assertException("register as JMX listener", RuntimeException.class,
-                    "Cannot register as JMX listener to netconf");
-
-            assertEquals(1 + 3, endpoint.getReceivedMessages().size());
-            assertCommitMessage(endpoint.getReceivedMessages().get(3));
-        }
+        NetconfOperation mockedOperation = mock(NetconfOperation.class);
+        doReturn(Sets.newHashSet(mockedOperation)).when(service).getNetconfOperations();
+        doReturn(HandlingPriority.getHandlingPriority(1)).when(mockedOperation).canHandle(any(Document.class));
+        doReturn(document).when(mockedOperation).handle(any(Document.class), any(NetconfOperationChainedExecution.class));
+        doNothing().when(service).close();
+        return service;
     }
 
-    private ConfigPusherConfiguration getConfigurationForSuccess() {
-        return getConfiguration(500, 1000)
-                    .withNetconfCapabilitiesWaitTimeoutMs(1000)
-                    .withNetconfPushConfigAttempts(3)
-                    .withNetconfPushConfigDelayMs(100)
-                    .withNetconfSendMessageMaxAttempts(3)
-                    .withNetconfSendMessageDelayMs(500).build();
+    private Document getOKDocument() throws SAXException, IOException {
+        return XmlUtil.readXmlToDocument(
+                "<rpc-reply message-id=\"1\" xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n" +
+                        "<ok/>\n" +
+                        "</rpc-reply>"
+        );
     }
 
+
     @Test
     public void testPersisterConflictingVersionException() throws Exception {
-        final TestingExceptionHandler handler = new TestingExceptionHandler();
-        ConfigPusherConfiguration cfg = getConfigurationWithOnePushAttempt();
-
-        setUpContextAndStartPersister(handler, "cap1", cfg);
-
-        try (MockNetconfEndpoint endpoint = startMockNetconfEndpoint("cap1", MockNetconfEndpoint.okMessage,
-                MockNetconfEndpoint.conflictingVersionErrorMessage); DefaultCommitNotificationProducer jMXNotifier = startJMXCommitNotifier();) {
-
-            Thread.sleep(4000);
-
-            handler.assertException("register as JMX listener", IllegalStateException.class,
-                    "Maximum attempt count has been reached for pushing", ConflictingVersionException.class, "Optimistic lock failed", 1);
-
-            assertEquals(1 + 3, endpoint.getReceivedMessages().size());
-            assertCommitMessage(endpoint.getReceivedMessages().get(3));
-        }
+        setUpContextAndStartPersister("cap1");
+        NetconfOperationService service = getWorkingService(getConflictVersionDocument());
+        doReturn(service).when(ctx.serviceFactory).createService(anyString());
+        Thread.sleep(2000);
+        handler.assertException(IllegalStateException.class, "Max wait for conflicting version stabilization timeout");
     }
 
-    @Test
-    public void testPersisterConflictingVersionExceptionThenSuccess() throws Exception {
-        final TestingExceptionHandler handler = new TestingExceptionHandler();
-        ConfigPusherConfiguration cfg = getConfigurationForSuccess();
-
-        setUpContextAndStartPersister(handler, "cap1", cfg);
-
-        MockNetconfEndpoint.MessageSequence conflictingMessageSequence = new MockNetconfEndpoint.MessageSequence(
-                MockNetconfEndpoint.okMessage, MockNetconfEndpoint.conflictingVersionErrorMessage);
-        MockNetconfEndpoint.MessageSequence okMessageSequence = new MockNetconfEndpoint.MessageSequence(
-                MockNetconfEndpoint.okMessage, MockNetconfEndpoint.okMessage);
-
-        try (MockNetconfEndpoint endpoint = startMockNetconfEndpoint("cap1",
-                Lists.newArrayList(conflictingMessageSequence, okMessageSequence));
-             DefaultCommitNotificationProducer jMXNotifier = startJMXCommitNotifier()) {
-
-            Thread.sleep(4000);
-
-            handler.assertNoException();
-
-            assertEquals(1 + 3/*Hello + Edit + Commit*/ + 3/*Hello + Edit + Commit*/, endpoint.getReceivedMessages().size());
-            assertCommitMessage(endpoint.getReceivedMessages().get(6));
-        }
+    private Document getConflictVersionDocument() throws SAXException, IOException {
+        return XmlUtil.readXmlToDocument(
+                "<rpc-reply message-id=\"1\" xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n" +
+                        "<rpc-error><error-info><error>" +
+                        ConflictingVersionException.class.getCanonicalName() +
+                        "</error></error-info></rpc-error>\n" +
+                        "</rpc-reply>"
+        );
     }
 
     @Test
-    public void testPersisterSuccessfulPushAndSuccessfulJMXRegistration() throws Exception {
-        final TestingExceptionHandler handler = new TestingExceptionHandler();
-        ConfigPusherConfiguration cfg = getConfigurationForSuccess();
-
-        setUpContextAndStartPersister(handler, "cap1", cfg);
-
-        try (MockNetconfEndpoint endpoint = startMockNetconfEndpoint("cap1", MockNetconfEndpoint.okMessage,
-                MockNetconfEndpoint.okMessage); DefaultCommitNotificationProducer jMXNotifier = startJMXCommitNotifier()) {
-
-            Thread.sleep(2000);
-
-            handler.assertNoException();
-
-            assertEquals(1 + 3, endpoint.getReceivedMessages().size());
-        }
-    }
-
-    private ConfigPusherConfigurationBuilder getConfiguration(int connectionAttemptDelayMs, int connectionAttemptTimeoutMs) {
-        return ConfigPusherConfigurationBuilder.aConfigPusherConfiguration()
-                .withEventLoopGroup(eventLoopGroup)
-                .withConnectionAttemptDelayMs(connectionAttemptDelayMs)
-                .withConnectionAttemptTimeoutMs(connectionAttemptTimeoutMs)
-                .withNetconfCapabilitiesWaitTimeoutMs(44)
-                .withNetconfAddress(new InetSocketAddress(NETCONF_ADDRESS, Integer.valueOf(NETCONF_PORT)));
+    public void testSuccessConflictingVersionException() throws Exception {
+        setUpContextAndStartPersister("cap1");
+        doReturn(getWorkingService(getConflictVersionDocument())).when(ctx.serviceFactory).createService(anyString());
+        Thread.sleep(500);
+        // working service:
+        logger.info("Switching to working service **");
+        doReturn(getWorkingService(getOKDocument())).when(ctx.serviceFactory).createService(anyString());
+        Thread.sleep(1000);
+        assertCannotRegisterAsJMXListener_pushWasSuccessful();
     }
 
-    private void waitTestToFinish(int i) throws InterruptedException {
-        Thread.sleep(i);
-    }
-
-
-    private DefaultCommitNotificationProducer startJMXCommitNotifier() {
-        return new DefaultCommitNotificationProducer(mBeanServer);
-    }
-
-    private void assertEditMessage(String netconfMessage) {
-        assertThat(netconfMessage,
-                JUnitMatchers.containsString(MockedBundleContext.DummyAdapterWithInitialSnapshot.CONFIG_SNAPSHOT));
-    }
-
-    private void assertCommitMessage(String netconfMessage) {
-        assertThat(netconfMessage, JUnitMatchers.containsString("<commit"));
-    }
-
-    private void assertHelloMessage(String netconfMessage) {
-        assertThat(netconfMessage,
-                JUnitMatchers.containsString("<hello xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">"));
-        assertThat(netconfMessage, JUnitMatchers.containsString("<capability>"));
-    }
-
-    private MockNetconfEndpoint startMockNetconfEndpoint(String capability, List<MockNetconfEndpoint.MessageSequence> messageSequences) {
-        // Add first empty sequence for testing connection created by config persister at startup
-        messageSequences.add(0, new MockNetconfEndpoint.MessageSequence(Collections.<String>emptyList()));
-        return new MockNetconfEndpoint(capability, NETCONF_PORT, messageSequences);
-    }
-
-    private MockNetconfEndpoint startMockNetconfEndpoint(String capability, String... messages) {
-        return startMockNetconfEndpoint(capability, Lists.newArrayList(new MockNetconfEndpoint.MessageSequence(messages)));
-    }
-
-    public ThreadFactory getThreadFactory(final Thread.UncaughtExceptionHandler exHandler) {
-        return new ThreadFactory() {
-            @Override
-            public Thread newThread(Runnable r) {
-                Thread thread = new Thread(r, "config-persister-testing-activator");
-                thread.setUncaughtExceptionHandler(exHandler);
-                return thread;
-            }
-        };
-    }
 }
diff --git a/opendaylight/netconf/config-persister-impl/src/test/java/org/opendaylight/controller/netconf/persist/impl/osgi/MockNetconfEndpoint.java b/opendaylight/netconf/config-persister-impl/src/test/java/org/opendaylight/controller/netconf/persist/impl/osgi/MockNetconfEndpoint.java
deleted file mode 100644 (file)
index 913db28..0000000
+++ /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.persist.impl.osgi;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.io.PrintWriter;
-import java.net.ServerSocket;
-import java.net.Socket;
-import java.net.SocketTimeoutException;
-import java.util.Collection;
-import java.util.List;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-import org.opendaylight.controller.netconf.util.test.XmlFileLoader;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
-
-import com.google.common.collect.Lists;
-
-class MockNetconfEndpoint implements AutoCloseable {
-
-    public static final int READ_SOCKET_TIMEOUT = 3000;
-
-    public static final String MSG_SEPARATOR = "]]>]]>\n";
-
-    private final AtomicBoolean stopped = new AtomicBoolean(false);
-    private List<String> receivedMessages = Lists.newCopyOnWriteArrayList();
-    private Thread innerThread;
-
-    MockNetconfEndpoint(String capability, String netconfPort, List<MessageSequence> messageSequence) {
-        helloMessage = helloMessage.replace("capability_place_holder", capability);
-        start(netconfPort, messageSequence);
-    }
-
-    private String helloMessage = "<hello xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n" +
-            "<capabilities>\n" +
-            "<capability>capability_place_holder</capability>\n" +
-            "</capabilities>\n" +
-            "<session-id>1</session-id>\n" +
-            "</hello>\n" +
-            MSG_SEPARATOR;
-
-    public static String conflictingVersionErrorMessage;
-    static {
-        try {
-            conflictingVersionErrorMessage = XmlUtil.toString(XmlFileLoader
-                    .xmlFileToDocument("netconfMessages/conflictingversion/conflictingVersionResponse.xml")) + MSG_SEPARATOR;
-        } catch (Exception e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    public static String okMessage = "<rpc-reply message-id=\"1\" xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n" +
-            "<ok/>\n" +
-            "</rpc-reply>" +
-            MSG_SEPARATOR ;
-
-    private void start(final String port, final List<MessageSequence> messagesToSend) {
-        innerThread = new Thread(new Runnable() {
-            @Override
-            public void run() {
-                int clientCounter = 0;
-
-                while (stopped.get() == false) {
-                    try (ServerSocket s = new ServerSocket(Integer.valueOf(port))) {
-                        s.setSoTimeout(READ_SOCKET_TIMEOUT);
-
-                        Socket clientSocket = s.accept();
-                        clientCounter++;
-                        clientSocket.setSoTimeout(READ_SOCKET_TIMEOUT);
-
-                        PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);
-                        BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
-
-                        // Negotiate
-                        sendMessage(out, helloMessage);
-                        receiveMessage(in);
-
-                        // Accept next message (edit-config)
-                        receiveMessage(in);
-
-                        for (String message : getMessageSequenceForClient(messagesToSend, clientCounter)) {
-                            sendMessage(out, message);
-                            receiveMessage(in);
-                        }
-                    } catch (SocketTimeoutException e) {
-                        // No more activity on netconf endpoint, close
-                        return;
-                    } catch (Exception e) {
-                        throw new RuntimeException(e);
-                    }
-                }
-            }
-
-            private Iterable<? extends String> getMessageSequenceForClient(List<MessageSequence> messagesToSend,
-                    int clientCounter) {
-                if (messagesToSend.size() <= clientCounter) {
-                    return messagesToSend.get(messagesToSend.size() - 1).getMessages();
-                } else {
-                    return messagesToSend.get(clientCounter - 1).getMessages();
-                }
-            }
-
-            private void receiveMessage(BufferedReader in) throws Exception {
-                String message = readMessage(in);
-                if(message == null || message.equals(""))
-                    return;
-                receivedMessages.add(message);
-            }
-
-            private String readMessage(BufferedReader in) throws IOException {
-                int c;
-                StringBuilder b = new StringBuilder();
-
-                while((c = in.read()) != -1) {
-                    b.append((char)c);
-                    if(b.toString().endsWith("]]>]]>"))
-                        break;
-                }
-
-                return b.toString();
-            }
-
-            private void sendMessage(PrintWriter out, String message) throws InterruptedException {
-                out.print(message);
-                out.flush();
-            }
-
-        });
-        innerThread.setName("Mocked-netconf-endpoint-inner-thread");
-        innerThread.start();
-    }
-
-    public List<String> getReceivedMessages() {
-        return receivedMessages;
-    }
-
-    public void close() throws IOException, InterruptedException {
-        stopped.set(true);
-        innerThread.join();
-    }
-
-    static class MessageSequence {
-        private List<String> messages;
-
-        MessageSequence(List<String> messages) {
-            this.messages = messages;
-        }
-
-        MessageSequence(String... messages) {
-            this(Lists.newArrayList(messages));
-        }
-
-        public Collection<String> getMessages() {
-            return messages;
-        }
-    }
-}
index 97cf7ecfe7e2f36763e1a96ad7f994cc87db9ea5..8bc787bdef39e571fc4cef62add5b0854c491130 100644 (file)
@@ -14,41 +14,71 @@ import org.mockito.MockitoAnnotations;
 import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
 import org.opendaylight.controller.config.persist.api.Persister;
 import org.opendaylight.controller.config.persist.api.PropertiesProvider;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactory;
 import org.opendaylight.controller.netconf.persist.impl.DummyAdapter;
+import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
+import org.osgi.framework.Filter;
+import org.osgi.framework.ServiceListener;
+import org.osgi.framework.ServiceReference;
 
 import java.io.IOException;
+import java.util.Collections;
 import java.util.List;
 import java.util.SortedSet;
 import java.util.TreeSet;
 
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.doReturn;
 
 final class MockedBundleContext {
-
     @Mock
     private BundleContext context;
+    @Mock
+    private Filter filter;
+    @Mock
+    private ServiceReference<?> serviceReference;
+    @Mock
+    private Bundle bundle;
+    @Mock
+    NetconfOperationServiceFactory serviceFactory;
+    @Mock
+    private NetconfOperationService service;
 
-    MockedBundleContext(String netconfAddress, String netconfPort) {
+    MockedBundleContext(long maxWaitForCapabilitiesMillis, long conflictingVersionTimeoutMillis) throws Exception {
         MockitoAnnotations.initMocks(this);
-        initContext(netconfAddress, netconfPort);
+        doReturn(null).when(context).getProperty(anyString());
+        initContext(maxWaitForCapabilitiesMillis, conflictingVersionTimeoutMillis);
+        doReturn(filter).when(context).createFilter(ConfigPersisterActivator.getFilterString());
+        String filterString = "filter";
+        doReturn(filterString).when(filter).toString();
+        doNothing().when(context).addServiceListener(any(ServiceListener.class), eq(filterString));
+        ServiceReference<?>[] toBeReturned = {serviceReference};
+        doReturn(toBeReturned).when(context).getServiceReferences((String) null, filterString);
+        doReturn(bundle).when(serviceReference).getBundle();
+        doReturn(context).when(bundle).getBundleContext();
+        doReturn("").when(serviceReference).toString();
+        doReturn(serviceFactory).when(context).getService(any(ServiceReference.class));
+        doReturn(service).when(serviceFactory).createService(anyString());
+        doReturn(Collections.emptySet()).when(service).getCapabilities();
+        doNothing().when(service).close();
     }
 
     public BundleContext getBundleContext() {
         return context;
     }
 
-    private void initContext(String netconfAddress, String netconfPort) {
-        initProp(context, ConfigPersisterActivator.IGNORED_MISSING_CAPABILITY_REGEX_SUFFIX, null);
-
-        initPropNoPrefix(context, "netconf.tcp.client.address", netconfAddress);
-        initPropNoPrefix(context, "netconf.tcp.client.port", netconfPort);
-
+    private void initContext(long maxWaitForCapabilitiesMillis, long conflictingVersionTimeoutMillis) {
         initProp(context, "active", "1");
         initProp(context, "1." + ConfigPersisterActivator.STORAGE_ADAPTER_CLASS_PROP_SUFFIX, DummyAdapterWithInitialSnapshot.class.getName());
         initProp(context, "1." + "readonly", "false");
         initProp(context, "1." + ".properties.fileStorage", "target/configuration-persister-test/initial/");
-
+        initProp(context, ConfigPersisterActivator.MAX_WAIT_FOR_CAPABILITIES_MILLIS_PROPERTY, String.valueOf(maxWaitForCapabilitiesMillis));
+        initProp(context, ConfigPersisterActivator.CONFLICTING_VERSION_TIMEOUT_MILLIS_PROPERTY, String.valueOf(conflictingVersionTimeoutMillis));
     }
 
     private void initProp(BundleContext context, String key, String value) {
@@ -66,7 +96,7 @@ final class MockedBundleContext {
 
         @Override
         public List<ConfigSnapshotHolder> loadLastConfigs() throws IOException {
-            return Lists.newArrayList(getConfigSnapshopt());
+            return Lists.newArrayList(getConfigSnapshot());
         }
 
         @Override
@@ -74,7 +104,7 @@ final class MockedBundleContext {
             return this;
         }
 
-        public ConfigSnapshotHolder getConfigSnapshopt() {
+        public ConfigSnapshotHolder getConfigSnapshot() {
             return new ConfigSnapshotHolder() {
                 @Override
                 public String getConfigSnapshot() {
index d42c15b8342736b0a523a7723d2e1d3b7865b15a..6fb231d847f2c5ae8c2022a7951460e19199ff70 100644 (file)
@@ -24,6 +24,10 @@ final class TestingExceptionHandler implements Thread.UncaughtExceptionHandler {
         this.t = e;
     }
 
+    public void assertException(Class<? extends Exception> exType, String exMessageToContain) {
+        assertException(exMessageToContain, exType, exMessageToContain);
+    }
+
     public void assertException(String failMessageSuffix, Class<? extends Exception> exType, String exMessageToContain) {
         if(t == null) {
             fail("Should fail to " + failMessageSuffix);
index 8d532d45e8a3c95153ad37e2fa9546d1fa8788c3..a35851445381f8bdcfd3142d036b9c3c34280d13 100644 (file)
@@ -7,12 +7,9 @@
  */
 package org.opendaylight.controller.netconf.impl.osgi;
 
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeMap;
-
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
 import org.opendaylight.controller.netconf.api.NetconfOperationRouter;
 import org.opendaylight.controller.netconf.api.NetconfSession;
@@ -33,9 +30,11 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.w3c.dom.Document;
 
-import com.google.common.base.Preconditions;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
 
 public class NetconfOperationRouterImpl implements NetconfOperationRouter {
 
@@ -186,18 +185,6 @@ public class NetconfOperationRouterImpl implements NetconfOperationRouter {
         return sortedPriority;
     }
 
-    public static final NetconfOperationChainedExecution EXECUTION_TERMINATION_POINT = new NetconfOperationChainedExecution() {
-        @Override
-        public boolean isExecutionTermination() {
-            return true;
-        }
-
-        @Override
-        public Document execute(Document requestMessage) throws NetconfDocumentedException {
-            throw new IllegalStateException("This execution represents the termination point in operation execution and cannot be executed itself");
-        }
-    };
-
     private static class NetconfOperationExecution implements NetconfOperationChainedExecution {
         private final NetconfOperation netconfOperation;
         private NetconfOperationChainedExecution subsequentExecution;
index cb4f53257e06f7e29d3989f6e3200232a9b4229e..5c08505091253282bdb638600b0ed656d3f2c319 100644 (file)
@@ -8,15 +8,15 @@
 
 package org.opendaylight.controller.netconf.impl.osgi;
 
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Set;
-
 import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService;
 import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactory;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
 public class NetconfOperationServiceSnapshot implements AutoCloseable {
     private static final Logger logger = LoggerFactory.getLogger(NetconfOperationServiceSnapshot.class);
 
@@ -27,7 +27,7 @@ public class NetconfOperationServiceSnapshot implements AutoCloseable {
         Set<NetconfOperationService> services = new HashSet<>();
         netconfSessionIdForReporting = getNetconfSessionIdForReporting(sessionId);
         for (NetconfOperationServiceFactory factory : factories) {
-            services.add(factory.createService(sessionId, netconfSessionIdForReporting));
+            services.add(factory.createService(netconfSessionIdForReporting));
         }
         this.services = Collections.unmodifiableSet(services);
     }
index 07da7f990a974df6dcfe8e1a62ddb68ae4d8987f..c1a7b1478b3edde41ea5f13004afc48df540c6bf 100644 (file)
@@ -111,7 +111,7 @@ public class ConcurrentClientsTest {
     private NetconfOperationServiceFactory mockOpF() {
         return new NetconfOperationServiceFactory() {
             @Override
-            public NetconfOperationService createService(long netconfSessionId, String netconfSessionIdForReporting) {
+            public NetconfOperationService createService(String netconfSessionIdForReporting) {
                 return new NetconfOperationService() {
                     @Override
                     public Set<Capability> getCapabilities() {
index 19007cd0371b6ad5198db5ab8681a8ffff1a7f3c..997cae0f7cf258a8a3074af1f525ea17347b1ce1 100644 (file)
@@ -22,13 +22,13 @@ import org.opendaylight.controller.config.manager.impl.factoriesresolver.Hardcod
 import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
 import org.opendaylight.controller.config.persist.api.Persister;
 import org.opendaylight.controller.config.spi.ModuleFactory;
-import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreException;
 import org.opendaylight.controller.netconf.api.NetconfMessage;
 import org.opendaylight.controller.netconf.api.jmx.CommitJMXNotification;
 import org.opendaylight.controller.netconf.api.monitoring.NetconfManagementSession;
 import org.opendaylight.controller.netconf.client.NetconfClient;
 import org.opendaylight.controller.netconf.client.NetconfClientDispatcher;
 import org.opendaylight.controller.netconf.confignetconfconnector.osgi.NetconfOperationServiceFactoryImpl;
+import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreException;
 import org.opendaylight.controller.netconf.impl.DefaultCommitNotificationProducer;
 import org.opendaylight.controller.netconf.impl.NetconfServerDispatcher;
 import org.opendaylight.controller.netconf.impl.osgi.NetconfMonitoringServiceImpl;
@@ -54,7 +54,6 @@ import java.net.InetSocketAddress;
 import java.util.Collection;
 import java.util.List;
 import java.util.Set;
-import java.util.regex.Pattern;
 
 import static junit.framework.Assert.assertEquals;
 import static org.mockito.Matchers.any;
@@ -124,7 +123,7 @@ public class NetconfConfigPersisterITTest extends AbstractNetconfConfigTest {
 
         try (NetconfClient persisterClient = new NetconfClient("persister", tcpAddress, 4000, clientDispatcher)) {
             try (ConfigPersisterNotificationHandler configPersisterNotificationHandler = new ConfigPersisterNotificationHandler(
-                    platformMBeanServer, mockedAggregator, Pattern.compile(""))) {
+                    platformMBeanServer, mockedAggregator)) {
 
 
                 try (NetconfClient netconfClient = new NetconfClient("client", tcpAddress, 4000, clientDispatcher)) {
index 5fd9f2fcd1ba6f1152c9ca7ef317b574ca47f706..ee971a65ddc882bd11e7c0593f1b3f0168bcce99 100644 (file)
@@ -44,6 +44,7 @@ import static org.opendaylight.controller.test.sal.binding.it.TestHelper.junitAn
 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.systemPackages;
 import static org.ops4j.pax.exam.CoreOptions.systemProperty;
 
 @RunWith(PaxExam.class)
@@ -62,6 +63,7 @@ public class IdentityRefNetconfTest {
                 systemProperty("osgi.console").value("2401"),
                 systemProperty("osgi.bundles.defaultStartLevel").value("4"),
                 systemProperty("pax.exam.osgi.unresolved.fail").value("true"),
+                systemPackages("sun.nio.ch"),
 
                 testingModules(),
                 loggingModules(),
index 1236138e6c6437a181b11425ac0f2f0449930944..05122be4d245a8f09b0c566aab90337c28c513af 100644 (file)
@@ -45,6 +45,10 @@ public class HandlingPriority implements Comparable<HandlingPriority> {
         return getHandlingPriority(priority + priorityIncrease);
     }
 
+    public boolean isCannotHandle() {
+        return this.equals(CANNOT_HANDLE);
+    }
+
     @Override
     public int compareTo(HandlingPriority o) {
         if (this == o)
index 22981530177dc57c2fd90bca03b7ea04880cd2c5..4013d623bd4c1dc1e891cd230fcb1b260c0f1ad6 100644 (file)
@@ -27,4 +27,18 @@ public interface NetconfOperationChainedExecution {
      * Do not execute if this is termination point
      */
     Document execute(Document requestMessage) throws NetconfDocumentedException;
+
+    public static final NetconfOperationChainedExecution EXECUTION_TERMINATION_POINT = new NetconfOperationChainedExecution() {
+        @Override
+        public boolean isExecutionTermination() {
+            return true;
+        }
+
+        @Override
+        public Document execute(Document requestMessage) throws NetconfDocumentedException {
+            throw new IllegalStateException("This execution represents the termination point in operation execution and cannot be executed itself");
+        }
+    };
+
+
 }
index 46b9cd22e06bb35cba2875fa6b05a9ca02b92454..81401f26eecc4796a61f2740b079a7351e33007a 100644 (file)
@@ -15,6 +15,6 @@ package org.opendaylight.controller.netconf.mapping.api;
  */
 public interface NetconfOperationServiceFactory {
 
-    NetconfOperationService createService(long netconfSessionId, String netconfSessionIdForReporting);
+    NetconfOperationService createService(String netconfSessionIdForReporting);
 
 }
index 11432314425e9db752be3bdde5eecb8b6cd4fa8c..de04484d1388f411577c7b1c2537996f2e625e7d 100644 (file)
@@ -46,7 +46,7 @@ public class NetconfMonitoringActivator implements BundleActivator {
         }
 
         @Override
-        public NetconfOperationService createService(long netconfSessionId, String netconfSessionIdForReporting) {
+        public NetconfOperationService createService(String netconfSessionIdForReporting) {
             return operationService;
         }
     }
index 796ab91a504040e87197f9032d85e4699d4c80b5..b0884ca2fb4bc648183841241967660c3f9fc9f3 100644 (file)
@@ -56,13 +56,17 @@ public final class NetconfUtil {
         return (doc == null) ? null : new NetconfMessage(doc);
     }
 
-    public static void checkIsMessageOk(NetconfMessage responseMessage) throws ConflictingVersionException {
-        XmlElement element = XmlElement.fromDomDocument(responseMessage.getDocument());
+    public static Document checkIsMessageOk(NetconfMessage responseMessage) throws ConflictingVersionException {
+        return checkIsMessageOk(responseMessage.getDocument());
+    }
+
+    public static Document checkIsMessageOk(Document response) throws ConflictingVersionException {
+        XmlElement element = XmlElement.fromDomDocument(response);
         Preconditions.checkState(element.getName().equals(XmlNetconfConstants.RPC_REPLY_KEY));
         element = element.getOnlyChildElement();
 
         if (element.getName().equals(XmlNetconfConstants.OK)) {
-            return;
+            return response;
         }
 
         if (element.getName().equals(XmlNetconfConstants.RPC_ERROR)) {
@@ -74,11 +78,11 @@ public final class NetconfUtil {
                 throw new ConflictingVersionException(error);
             }
             throw new IllegalStateException("Can not load last configuration, operation failed: "
-                    + XmlUtil.toString(responseMessage.getDocument()));
+                    + XmlUtil.toString(response));
         }
 
         logger.warn("Can not load last configuration. Operation failed.");
         throw new IllegalStateException("Can not load last configuration. Operation failed: "
-                + XmlUtil.toString(responseMessage.getDocument()));
+                + XmlUtil.toString(response));
     }
 }
index e7b9a025520f3d5ab64fa03b2852a9dc1ce61172..586366f41a63659bc8b75fd8ccbf12df97ae34bd 100644 (file)
@@ -47,7 +47,6 @@
         <osgi.version>5.0.0</osgi.version>
         <maven.bundle.version>2.4.0</maven.bundle.version>
         <slf4j.version>1.7.2</slf4j.version>
-        <netconf.netty.version>4.0.10.Final</netconf.netty.version>
         <salGeneratorPath>${project.build.directory}/generated-sources/sal</salGeneratorPath>
     </properties>
 
index 9ef56e5dc440b612f5f70e0ec823fca3172aad2c..9ddba67e251360996d6c72e50ad81e271c1c0f65 100644 (file)
@@ -29,6 +29,7 @@ import org.opendaylight.controller.northbound.commons.exception.NotAcceptableExc
 import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException;
 import org.opendaylight.controller.northbound.commons.exception.ServiceUnavailableException;
 import org.opendaylight.controller.sal.core.Node;
+import org.opendaylight.controller.sal.networkconfig.bridgedomain.BridgeDomainConfigServiceException;
 import org.opendaylight.controller.sal.networkconfig.bridgedomain.ConfigConstants;
 import org.opendaylight.controller.sal.networkconfig.bridgedomain.IBridgeDomainConfigService;
 import org.opendaylight.controller.sal.utils.ServiceHelper;
@@ -114,9 +115,7 @@ public class BridgeDomainNorthbound {
            if (status.getCode().equals(StatusCode.SUCCESS)) {
                return Response.status(Response.Status.CREATED).build();
            }
-       } catch (Error e) {
-           throw e;
-       } catch (Throwable t) {
+       } catch (BridgeDomainConfigServiceException e) {
            return Response.status(Response.Status.PRECONDITION_FAILED).build();
        }
        throw new ResourceNotFoundException(status.getDescription());
diff --git a/opendaylight/sal/networkconfiguration/api/src/main/java/org/opendaylight/controller/sal/networkconfig/bridgedomain/BridgeDomainConfigServiceException.java b/opendaylight/sal/networkconfiguration/api/src/main/java/org/opendaylight/controller/sal/networkconfig/bridgedomain/BridgeDomainConfigServiceException.java
new file mode 100644 (file)
index 0000000..19f467e
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * 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.networkconfig.bridgedomain;
+
+/**
+ * Exception thrown by IPluginInBridgeDomainConfigService implementations.
+ */
+public class BridgeDomainConfigServiceException extends Exception {
+    private static final long serialVersionUID = 1L;
+
+    public BridgeDomainConfigServiceException(String message) {
+        super(message);
+    }
+
+    public BridgeDomainConfigServiceException(String message, Throwable cause) {
+        super(message, cause);
+    }
+}
+
index f8696b1cec347372d7cb27b8b28d43ee22eb38cb..c84136115c434c0a26367afcf1a438670e37f119 100644 (file)
@@ -29,7 +29,7 @@ public interface IPluginInBridgeDomainConfigService {
      * @note This method will return false if one or more of the supplied params is not supported by the
      * protocol plugin that serves the Node.
      */
-    public Status createBridgeDomain(Node node, String bridgeIdentifier, Map<ConfigConstants, Object> params) throws Throwable;
+    public Status createBridgeDomain(Node node, String bridgeIdentifier, Map<ConfigConstants, Object> params) throws BridgeDomainConfigServiceException;
 
     /**
      * Delete a Bridge Domain
index 64c72115f61519895ea3d8e3e44121b646319b77..14c5e0d9e72ada56a7d8d4c2f55e477e2a5f95f1 100644 (file)
@@ -14,6 +14,7 @@ import java.util.concurrent.ConcurrentMap;
 
 import org.opendaylight.controller.sal.core.Node;
 import org.opendaylight.controller.sal.core.NodeConnector;
+import org.opendaylight.controller.sal.networkconfig.bridgedomain.BridgeDomainConfigServiceException;
 import org.opendaylight.controller.sal.networkconfig.bridgedomain.ConfigConstants;
 import org.opendaylight.controller.sal.networkconfig.bridgedomain.IBridgeDomainConfigService;
 import org.opendaylight.controller.sal.networkconfig.bridgedomain.IPluginInBridgeDomainConfigService;
@@ -26,7 +27,7 @@ import org.slf4j.LoggerFactory;
 public class BridgeDomainConfigService implements IBridgeDomainConfigService {
     protected static final Logger logger = LoggerFactory
             .getLogger(BridgeDomainConfigService.class);
-    private ConcurrentMap<String, IPluginInBridgeDomainConfigService> pluginService =
+    private final ConcurrentMap<String, IPluginInBridgeDomainConfigService> pluginService =
             new ConcurrentHashMap<String, IPluginInBridgeDomainConfigService>();
 
     void setPluginInService (Map props, IPluginInBridgeDomainConfigService s) {
@@ -80,7 +81,7 @@ public class BridgeDomainConfigService implements IBridgeDomainConfigService {
 
     @Override
     public Status createBridgeDomain(Node node, String bridgeIdentifier, Map<ConfigConstants, Object> params)
-            throws Throwable {
+            throws BridgeDomainConfigServiceException {
         if (pluginService != null) {
             IPluginInBridgeDomainConfigService plugin = this.pluginService.get(node.getType());
             if (plugin != null) {
index e4bb790676379bfb508ea6b6eec4051a38286636..a9f11fafb5c2ae2e9434dc24f232f21b1a3b59d1 100644 (file)
@@ -774,7 +774,7 @@ public class Devices implements IDaylightWeb {
         return result;
     }
 
-    @RequestMapping(value = "/connect/{nodeId}", method = RequestMethod.POST)
+    @RequestMapping(value = "/connect/{nodeId:.+}", method = RequestMethod.POST)
     @ResponseBody
     public Status addNode(HttpServletRequest request, @PathVariable("nodeId") String nodeId,
             @RequestParam(required = true) String ipAddress, @RequestParam(required = true) String port,
@@ -811,7 +811,7 @@ public class Devices implements IDaylightWeb {
         return new Status(StatusCode.SUCCESS);
     }
 
-    @RequestMapping(value = "/disconnect/{nodeId}", method = RequestMethod.POST)
+    @RequestMapping(value = "/disconnect/{nodeId:.+}", method = RequestMethod.POST)
     @ResponseBody
     public Status removeNode(HttpServletRequest request, @PathVariable("nodeId") String nodeId,
             @RequestParam(required = true) String nodeType) {
index 4304d76b0d5630774ad98d0d121d31765bafd406..9c3c895916b03f88c579996d91d27c15b842776c 100644 (file)
@@ -363,7 +363,6 @@ public class Flows implements IDaylightWeb {
         SupportedFlowActions supportedFlows = (SupportedFlowActions) switchManager.getNodeProp(node, "supportedFlowActions");
         List<Class<? extends Action>> actions = supportedFlows.getActions();
         for (Class<? extends Action> action : actions) {
-            String actionName = action.getSimpleName().toLowerCase();
             if (action.isAssignableFrom(org.opendaylight.controller.sal.action.Drop.class)) {
                 result.put(ActionType.DROP.toString(), "Drop");
             } else if (action.isAssignableFrom(org.opendaylight.controller.sal.action.Loopback.class)) {
index 61d77489769742c32b6b261f1ee32e274724ceb7..6e7fd25e049a17fc997b30c5d2003227e1b9a61f 100644 (file)
@@ -303,6 +303,11 @@ one.f.flows = {
         modifyTosBits : "one_f_flows_modal_action_modifyTosBits",
         modifyTransportSourcePort : "one_f_flows_modal_action_modifyTransportSourcePort",
         modifyTransportDestinationPort : "one_f_flows_modal_action_modifyTransportDestinationPort",
+        enqueue : 'one-f-flows-modal-action-enqueue',
+        queue : 'one-f-flows-modal-action-queue',
+        setEthertype : 'one-f-flows-modal-action-setEthertype',
+        pushVlan : 'one-f-flows-modal-action-pushVlan',
+        setVlanCfi : 'one-f-flows-modal-action-setVlanCfi',
         modal : {
           modal : "one_f_flows_modal_action_modal_modal",
           remove : "one_f_flows_modal_action_modal_remove",
@@ -1052,7 +1057,7 @@ one.f.flows = {
           case "SET_VLAN_CFI" :
             var h3 = "Set VLAN CFI";
             var placeholder = "VLAN CFI";
-            var id = one.f.flows.id.modal.action.setVlanPriority;
+            var id = one.f.flows.id.modal.action.setVlanCfi;
             var help = "Range: 0 - 1";
             var action = 'SET_VLAN_CFI';
             var name = "VLAN CFI";
@@ -1073,7 +1078,7 @@ one.f.flows = {
           case "PUSH_VLAN" :
             var h3 = "Push VLAN";
             var placeholder = "VLAN";
-            var id = one.f.flows.id.modal.action.setVlanPriority;
+            var id = one.f.flows.id.modal.action.pushVlan;
             var help = "Range: 0 - 4095";
             var action = 'PUSH_VLAN';
             var name = "VLAN";
@@ -1121,7 +1126,7 @@ one.f.flows = {
           case "SET_DL_TYPE" :
             var h3 = "Set Ethertype";
             var placeholder = "Ethertype";
-            var id = one.f.flows.id.modal.action.setVlanPriority;
+            var id = one.f.flows.id.modal.action.setEthertype;
             var help = "Range: 0 - 65535";
             var action = 'SET_DL_TYPE';
             var name = "Ethertype";
@@ -1214,6 +1219,13 @@ one.f.flows = {
             var $modal = one.f.flows.modal.action.initialize(h3, body, add);
             $modal.modal();
             break;
+          case "ENQUEUE" :
+            var h3 = "Enqueue";
+            var placeholder = "Enqueue";
+            var id = one.f.flows.id.modal.action.enqueue;
+            var $modal = one.f.flows.modal.action.initialize(h3, one.f.flows.modal.action.body.addEnqueue, one.f.flows.modal.action.add.addEnqueue);
+            $modal.modal();
+            break;
           case "DROP" :
             var name = "Drop";
             var action = 'DROP';
@@ -1249,11 +1261,6 @@ one.f.flows = {
             var action = 'CONTROLLER';
             one.f.flows.modal.action.add.add(name, action);
             break;
-          case "ENQUEUE" :
-            var name = "Enqueue";
-            var action = 'ENQUEUE';
-            one.f.flows.modal.action.add.add(name, action);
-            break;
         }
       },
       initialize : function(h3, bodyCallback, addCallback) {
@@ -1284,6 +1291,37 @@ one.f.flows = {
           one.f.flows.modal.action.add.addPortsToTable(ports, pid);
           $modal.modal('hide');
         },
+        addEnqueue : function($modal) {
+          var $options = $('#'+one.f.flows.id.modal.action.addOutputPorts).find('option:selected');
+          var ports = '';
+          var pid = '';
+          $options.each(function(index, value) {
+            ports = ports+$(value).text()+", ";
+            pid = pid+$(value).attr('value')+",";
+          });
+          var $input = $('#'+one.f.flows.id.modal.action.queue);
+          var queue = $input.val();
+          ports = ports.slice(0,-2);
+          pid = pid.slice(0,-1);
+          one.f.flows.modal.action.add.addEnqueueToTable(ports, pid, queue);
+          $modal.modal('hide');
+        },
+        addEnqueueToTable : function(ports, pid, queue) {
+          if (queue !== '' && queue >= 0) {
+            ports += ':'+queue;
+          }
+          var $tr = one.f.flows.modal.action.table.add("Enqueue", ports);
+          $tr.attr('id', 'ENQUEUE');
+          if (queue !== '' && queue >= 0) {
+            $tr.data('action', 'ENQUEUE='+pid+':'+queue);
+          } else {
+            $tr.data('action', 'ENQUEUE='+pid+':0'); // default queue to 0
+          }
+          $tr.click(function() {
+            one.f.flows.modal.action.add.modal.initialize(this);
+          });
+          one.f.flows.modal.action.table.append($tr);
+        },
         addPortsToTable : function(ports, pid){
           var $tr = one.f.flows.modal.action.table.add("Add Output Ports", ports);
           $tr.attr('id', 'OUTPUT');
@@ -1410,6 +1448,27 @@ one.f.flows = {
           $form.append($fieldset);
           return $form;
         },
+        addEnqueue : function() {
+          var common = one.f.flows.modal.action.body.common();
+          var $form = common[0];
+          var $fieldset = common[1];
+          // output port
+          $label = one.lib.form.label("Select Output Ports");
+          if (one.f.flows.registry.currentNode == undefined){
+            return; //Selecting Output ports without selecting node throws an exception
+          }
+          var ports = one.f.flows.registry.nodeports[one.f.flows.registry.currentNode]['ports'];
+          $select = one.lib.form.select.create(ports);
+          $select.attr('id', one.f.flows.id.modal.action.addOutputPorts);
+          $fieldset.append($label).append($select);
+          $label = one.lib.form.label('Queue (Optional)');
+          $input = one.lib.form.input('Queue')
+          .attr('id', one.f.flows.id.modal.action.queue);
+          $help = one.lib.form.help('Range: 1 - 2147483647');
+          $fieldset.append($label).append($input).append($help);
+          $form.append($fieldset);
+          return $form;
+        },
         set : function(label, placeholder, id, help) {
           var common = one.f.flows.modal.action.body.common();
           var $form = common[0];