Merge "Migrate toaster samples to config-subsystem"
authorTony Tkacik <ttkacik@cisco.com>
Wed, 26 Feb 2014 13:41:31 +0000 (13:41 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Wed, 26 Feb 2014 13:41:32 +0000 (13:41 +0000)
58 files changed:
opendaylight/commons/opendaylight/pom.xml
opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/AbstractProtocolSession.java
opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/AbstractSessionNegotiator.java
opendaylight/config/config-api/src/main/java/org/opendaylight/controller/config/spi/Module.java
opendaylight/config/config-manager/pom.xml
opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/CommitInfo.java
opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ConfigRegistryImpl.java
opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ConfigTransactionControllerImpl.java
opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ConfigTransactionControllerInternal.java
opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/DeadlockMonitor.java [new file with mode: 0644]
opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ModuleInternalInfo.java
opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dependencyresolver/DependencyResolverImpl.java
opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dependencyresolver/DependencyResolverManager.java
opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dependencyresolver/DestroyedModule.java [moved from opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/DestroyedModule.java with 94% similarity]
opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dependencyresolver/ModuleInternalTransactionalInfo.java [moved from opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/ModuleInternalTransactionalInfo.java with 75% similarity]
opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dependencyresolver/ModulesHolder.java
opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dependencyresolver/TransactionHolder.java [deleted file]
opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/mapping/ModuleInfoBundleTracker.java
opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/impl/dependencyresolver/DependencyResolverManagerTest.java
opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/parallelapsp/TestingParallelAPSPModule.java
opendaylight/config/config-manager/src/test/java/org/opendaylight/controller/config/manager/testingservices/threadpool/test/SimpleConfigurationTest.java
opendaylight/config/netty-event-executor-config/src/main/java/org/opendaylight/controller/config/yang/netty/eventexecutor/AutoCloseableEventExecutor.java [new file with mode: 0644]
opendaylight/config/netty-event-executor-config/src/main/java/org/opendaylight/controller/config/yang/netty/eventexecutor/GlobalEventExecutorModule.java
opendaylight/config/netty-event-executor-config/src/main/java/org/opendaylight/controller/config/yang/netty/eventexecutor/ImmediateEventExecutorModule.java [new file with mode: 0644]
opendaylight/config/netty-event-executor-config/src/main/java/org/opendaylight/controller/config/yang/netty/eventexecutor/ImmediateEventExecutorModuleFactory.java [new file with mode: 0644]
opendaylight/config/netty-event-executor-config/src/main/yang/netty-event-executor.yang
opendaylight/md-sal/pom.xml
opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/data/DataBrokerService.java
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/DataBrokerImpl.java
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/DeprecatedDataAPISupport.xtend [deleted file]
opendaylight/md-sal/sal-binding-util/src/main/java/org/opendaylight/controller/md/sal/binding/util/AbstractBindingSalConsumerInstance.java
opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataCommitHandler.java
opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/TwoPhaseCommit.java
opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/RpcImplementation.java
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/SchemaAwareDataStoreAdapter.java
opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/binding/impl/DataBrokerServiceImpl.java
opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/impl/DataBrokerServiceImpl.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/Commit.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/osgi/Activator.java
opendaylight/netconf/config-persister-impl/pom.xml
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 [new file with mode: 0644]
opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/ConfigPusherConfigurationBuilder.java [new file with mode: 0644]
opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/PersisterAggregator.java
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/osgi/ConfigPersisterTest.java [new file with mode: 0644]
opendaylight/netconf/config-persister-impl/src/test/java/org/opendaylight/controller/netconf/persist/impl/osgi/MockNetconfEndpoint.java [new file with mode: 0644]
opendaylight/netconf/config-persister-impl/src/test/java/org/opendaylight/controller/netconf/persist/impl/osgi/MockedBundleContext.java [new file with mode: 0644]
opendaylight/netconf/config-persister-impl/src/test/java/org/opendaylight/controller/netconf/persist/impl/osgi/TestingExceptionHandler.java [new file with mode: 0644]
opendaylight/netconf/netconf-util/src/test/java/org/opendaylight/controller/netconf/util/test/XmlFileLoader.java
opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronFloatingIPsNorthbound.java
opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronNetworksNorthbound.java
opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronPortsNorthbound.java
opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronRoutersNorthbound.java
opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronSubnetsNorthbound.java
opendaylight/sal/api/pom.xml
opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/core/Edge.java
opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/core/Path.java

index 43e254c88d2ad366b9a76c662a17c7fefef664fa..acda40035f425d24c829957ff40e65bf038393bb 100644 (file)
@@ -84,7 +84,7 @@
     <containermanager.it.version>0.5.2-SNAPSHOT</containermanager.it.version>
     <switchmanager.api.version>0.7.1-SNAPSHOT</switchmanager.api.version>
     <connectionmanager.version>0.1.2-SNAPSHOT</connectionmanager.version>
-    <sal.version>0.7.1-SNAPSHOT</sal.version>
+    <sal.version>0.8.1-SNAPSHOT</sal.version>
     <sal.networkconfiguration.version>0.0.3-SNAPSHOT</sal.networkconfiguration.version>
     <sal.connection.version>0.1.2-SNAPSHOT</sal.connection.version>
     <networkconfig.bridgedomain.northbound.version>0.0.3-SNAPSHOT</networkconfig.bridgedomain.northbound.version>
index e7bd66574036111c72a0ddad5291afdd905e1ac7..47e96d1ff490df392accfb84dc10d55eb84a4583 100644 (file)
@@ -40,6 +40,7 @@ public abstract class AbstractProtocolSession<M> extends SimpleChannelInboundHan
     }
 
     @Override
+    @SuppressWarnings("unchecked")
     protected final void channelRead0(final ChannelHandlerContext ctx, final Object msg) {
         LOG.debug("Message was received: {}", msg);
         handleMessage((M) msg);
index d41e8106c5aec85166b43d72241b7fb600921801..cbe923524516077497f806fdad9b74c4d84e9927 100644 (file)
@@ -85,6 +85,7 @@ public abstract class AbstractSessionNegotiator<M, S extends AbstractProtocolSes
     }
 
     @Override
+    @SuppressWarnings("unchecked")
     public final void channelRead(final ChannelHandlerContext ctx, final Object msg) {
         LOG.debug("Negotiation read invoked on channel {}", channel);
         try {
index dd11b7503f0e09d8af7710cf89bd6ccdaab0ec74..1b16ec828432624b120228c4cacfd91479a0406e 100644 (file)
@@ -7,11 +7,11 @@
  */
 package org.opendaylight.controller.config.spi;
 
-import javax.annotation.concurrent.NotThreadSafe;
-
 import org.opendaylight.controller.config.api.ModuleIdentifier;
 import org.opendaylight.yangtools.concepts.Identifiable;
 
+import javax.annotation.concurrent.NotThreadSafe;
+
 
 /**
  * Represents one service that is to be configured. These methods need to be
@@ -20,7 +20,7 @@ import org.opendaylight.yangtools.concepts.Identifiable;
  * ConfigBeans.
  * <p>
  * In order to guide dependency resolution, the setter method should be
- * annotated with {@link RequireInterface}.
+ * annotated with {@link org.opendaylight.controller.config.api.annotations.RequireInterface}.
  * </p>
  * <p>
  * Thread safety note: implementations of this interface are not required to be
@@ -43,10 +43,10 @@ public interface Module extends Identifiable<ModuleIdentifier>{
      * Returns 'live' object that was configured using this object. It is
      * allowed to call this method only after all ConfigBeans were validated. In
      * this method new resources might be opened or old instance might be
-     * modified. Note that when obtaining dependent Module using
-     * {@link org.opendaylight.controller.config.api.DependencyResolver#validateDependency(Class, javax.management.ObjectName, String)}
-     * a proxy will be created that will disallow calling this method before
-     * second commit phase begins.
+     * modified. This method must be implemented so that it returns same
+     * result for a single transaction. Since Module is created per transaction
+     * this means that it must be safe to cache result of first call.
+     *
      *
      * @return closeable instance: After bundle update the factory might be able
      *         to copy old configuration into new one without being able to cast
index 4857f2a2016127cc492ad6d87af45fff1ea4880f..7d7d9d697adb8de75638d8604eae81f28c35a481 100644 (file)
@@ -68,7 +68,6 @@
         <dependency>
             <groupId>com.google.guava</groupId>
             <artifactId>guava</artifactId>
-            <scope>test</scope>
         </dependency>
         <dependency>
             <groupId>org.opendaylight.yangtools</groupId>
index 9d086295e3c30fc9b5524357b8e0c1ca3dc96d0a..28732d8f68ea6e53832e954ff388681c608bc26b 100644 (file)
@@ -14,6 +14,8 @@ import java.util.Map;
 import javax.annotation.concurrent.Immutable;
 
 import org.opendaylight.controller.config.api.ModuleIdentifier;
+import org.opendaylight.controller.config.manager.impl.dependencyresolver.DestroyedModule;
+import org.opendaylight.controller.config.manager.impl.dependencyresolver.ModuleInternalTransactionalInfo;
 
 /**
  * Structure obtained during first phase commit, contains destroyed modules from
index 8f6a4654b26d2d9f2548c38e91ea9b82445b326f..dd510a1ed7099a3e087e7e4aa935b0881d6f84fb 100644 (file)
@@ -7,6 +7,7 @@
  */
 package org.opendaylight.controller.config.manager.impl;
 
+import com.google.common.collect.Maps;
 import org.opendaylight.controller.config.api.ConflictingVersionException;
 import org.opendaylight.controller.config.api.ModuleIdentifier;
 import org.opendaylight.controller.config.api.RuntimeBeanRegistratorAwareModule;
@@ -14,6 +15,8 @@ import org.opendaylight.controller.config.api.ServiceReferenceWritableRegistry;
 import org.opendaylight.controller.config.api.ValidationException;
 import org.opendaylight.controller.config.api.jmx.CommitStatus;
 import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
+import org.opendaylight.controller.config.manager.impl.dependencyresolver.DestroyedModule;
+import org.opendaylight.controller.config.manager.impl.dependencyresolver.ModuleInternalTransactionalInfo;
 import org.opendaylight.controller.config.manager.impl.dynamicmbean.DynamicReadableWrapper;
 import org.opendaylight.controller.config.manager.impl.factoriesresolver.HierarchicalConfigMBeanFactoriesHolder;
 import org.opendaylight.controller.config.manager.impl.factoriesresolver.ModuleFactoriesResolver;
@@ -119,13 +122,13 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe
                               MBeanServer configMBeanServer,
                               BaseJMXRegistrator baseJMXRegistrator, CodecRegistry codecRegistry) {
         this.resolver = resolver;
-        beanToOsgiServiceManager = new BeanToOsgiServiceManager();
+        this.beanToOsgiServiceManager = new BeanToOsgiServiceManager();
         this.configMBeanServer = configMBeanServer;
         this.baseJMXRegistrator = baseJMXRegistrator;
         this.codecRegistry = codecRegistry;
-        registryMBeanServer = MBeanServerFactory
+        this.registryMBeanServer = MBeanServerFactory
                 .createMBeanServer("ConfigRegistry" + configMBeanServer.getDefaultDomain());
-        transactionsMBeanServer = MBeanServerFactory
+        this.transactionsMBeanServer = MBeanServerFactory
                 .createMBeanServer("ConfigTransactions" + configMBeanServer.getDefaultDomain());
     }
 
@@ -173,7 +176,7 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe
             throw new IllegalStateException(e);
         }
         transactionController.copyExistingModulesAndProcessFactoryDiff(currentConfig.getEntries(), lastListOfFactories);
-        transactionsHolder.add(transactionName, transactionController);
+        transactionsHolder.add(transactionName, transactionController, txLookupRegistry);
         return transactionController;
     }
 
@@ -189,12 +192,13 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe
         logger.trace("About to commit {}. Current parentVersion: {}, versionCounter {}", transactionName, version, versionCounter);
 
         // find ConfigTransactionController
-        Map<String, ConfigTransactionControllerInternal> transactions = transactionsHolder.getCurrentTransactions();
-        ConfigTransactionControllerInternal configTransactionController = transactions.get(transactionName);
-        if (configTransactionController == null) {
+        Map<String, Entry<ConfigTransactionControllerInternal, ConfigTransactionLookupRegistry>> transactions = transactionsHolder.getCurrentTransactions();
+        Entry<ConfigTransactionControllerInternal, ConfigTransactionLookupRegistry> configTransactionControllerEntry = transactions.get(transactionName);
+        if (configTransactionControllerEntry == null) {
             throw new IllegalArgumentException(String.format(
                     "Transaction with name '%s' not found", transactionName));
         }
+        ConfigTransactionControllerInternal configTransactionController = configTransactionControllerEntry.getKey();
         // check optimistic lock
         if (version != configTransactionController.getParentVersion()) {
             throw new ConflictingVersionException(
@@ -209,8 +213,7 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe
         lastListOfFactories = Collections.unmodifiableList(configTransactionController.getCurrentlyRegisteredFactories());
         // non recoverable from here:
         try {
-            return secondPhaseCommit(
-                    configTransactionController, commitInfo);
+            return secondPhaseCommit(configTransactionController, commitInfo, configTransactionControllerEntry.getValue());
         } catch (Throwable t) { // some libs throw Errors: e.g.
             // javax.xml.ws.spi.FactoryFinder$ConfigurationError
             isHealthy = false;
@@ -220,13 +223,13 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe
             } else if (t instanceof Error) {
                 throw (Error) t;
             } else {
-                throw new IllegalStateException(t);
+                throw new RuntimeException(t);
             }
         }
     }
 
     private CommitStatus secondPhaseCommit(ConfigTransactionControllerInternal configTransactionController,
-                                           CommitInfo commitInfo) {
+                                           CommitInfo commitInfo, ConfigTransactionLookupRegistry txLookupRegistry) {
 
         // close instances which were destroyed by the user, including
         // (hopefully) runtime beans
@@ -255,7 +258,7 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe
                         .getRuntimeBeanRegistrator();
             }
             // set runtime jmx registrator if required
-            Module module = entry.getModule();
+            Module module = entry.getProxiedModule();
             if (module instanceof RuntimeBeanRegistratorAwareModule) {
                 ((RuntimeBeanRegistratorAwareModule) module)
                         .setRuntimeBeanRegistrator(runtimeBeanRegistrator);
@@ -265,8 +268,9 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe
         }
 
         // can register runtime beans
-        List<ModuleIdentifier> orderedModuleIdentifiers = configTransactionController
-                .secondPhaseCommit();
+        List<ModuleIdentifier> orderedModuleIdentifiers = configTransactionController.secondPhaseCommit();
+        txLookupRegistry.close();
+        configTransactionController.close();
 
         // copy configuration to read only mode
         List<ObjectName> newInstances = new LinkedList<>();
@@ -283,7 +287,7 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe
                 throw new NullPointerException("Module not found "
                         + moduleIdentifier);
             }
-            Module module = entry.getModule();
+
             ObjectName primaryReadOnlyON = ObjectNameUtil
                     .createReadOnlyModuleON(moduleIdentifier);
 
@@ -300,13 +304,14 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe
                     .createModuleJMXRegistrator();
 
             OsgiRegistration osgiRegistration = null;
+            AutoCloseable instance = entry.getProxiedModule().getInstance();
             if (entry.hasOldModule()) {
                 ModuleInternalInfo oldInternalInfo = entry.getOldInternalInfo();
                 DynamicReadableWrapper oldReadableConfigBean = oldInternalInfo.getReadableModule();
                 currentConfig.remove(entry.getIdentifier());
 
                 // test if old instance == new instance
-                if (oldReadableConfigBean.getInstance().equals(module.getInstance())) {
+                if (oldReadableConfigBean.getInstance().equals(instance)) {
                     // reused old instance:
                     // wrap in readable dynamic mbean
                     reusedInstances.add(primaryReadOnlyON);
@@ -328,9 +333,10 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe
                 // wrap in readable dynamic mbean
                 newInstances.add(primaryReadOnlyON);
             }
+            Module realModule = entry.getRealModule();
 
             DynamicReadableWrapper newReadableConfigBean = new DynamicReadableWrapper(
-                    module, module.getInstance(), moduleIdentifier,
+                    realModule, instance, moduleIdentifier,
                     registryMBeanServer, configMBeanServer);
 
             // register to JMX
@@ -347,7 +353,7 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe
                 if (moduleFactory != null) {
                     BundleContext bc = configTransactionController.
                             getModuleFactoryBundleContext(moduleFactory.getImplementationName());
-                    osgiRegistration = beanToOsgiServiceManager.registerToOsgi(module.getClass(),
+                    osgiRegistration = beanToOsgiServiceManager.registerToOsgi(realModule.getClass(),
                             newReadableConfigBean.getInstance(), entry.getIdentifier(), bc);
                 } else {
                     throw new NullPointerException(entry.getIdentifier().getFactoryName() + " ModuleFactory not found.");
@@ -362,7 +368,7 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe
                     runtimeBeanRegistrator, newModuleJMXRegistrator,
                     orderingIdx, entry.isDefaultBean());
 
-            newConfigEntries.put(module, newInfo);
+            newConfigEntries.put(realModule, newInfo);
             orderingIdx++;
         }
         currentConfig.addAll(newConfigEntries.values());
@@ -371,8 +377,8 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe
         version = configTransactionController.getVersion();
 
         // switch readable Service Reference Registry
-        readableSRRegistry.close();
-        readableSRRegistry = ServiceReferenceRegistryImpl.createSRReadableRegistry(
+        this.readableSRRegistry.close();
+        this.readableSRRegistry = ServiceReferenceRegistryImpl.createSRReadableRegistry(
                 configTransactionController.getWritableRegistry(), this, baseJMXRegistrator);
 
         return new CommitStatus(newInstances, reusedInstances,
@@ -384,12 +390,12 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe
      */
     @Override
     public synchronized List<ObjectName> getOpenConfigs() {
-        Map<String, ConfigTransactionControllerInternal> transactions = transactionsHolder
+        Map<String, Entry<ConfigTransactionControllerInternal, ConfigTransactionLookupRegistry>> transactions = transactionsHolder
                 .getCurrentTransactions();
         List<ObjectName> result = new ArrayList<>(transactions.size());
-        for (ConfigTransactionControllerInternal configTransactionController : transactions
+        for (Entry<ConfigTransactionControllerInternal, ConfigTransactionLookupRegistry> configTransactionControllerEntry : transactions
                 .values()) {
-            result.add(configTransactionController.getControllerObjectName());
+            result.add(configTransactionControllerEntry.getKey().getControllerObjectName());
         }
         return result;
     }
@@ -403,11 +409,14 @@ public class ConfigRegistryImpl implements AutoCloseable, ConfigRegistryImplMXBe
     @Override
     public synchronized void close() {
         // abort transactions
-        Map<String, ConfigTransactionControllerInternal> transactions = transactionsHolder
+        Map<String, Entry<ConfigTransactionControllerInternal, ConfigTransactionLookupRegistry>> transactions = transactionsHolder
                 .getCurrentTransactions();
-        for (ConfigTransactionControllerInternal configTransactionController : transactions
+        for (Entry<ConfigTransactionControllerInternal, ConfigTransactionLookupRegistry> configTransactionControllerEntry : transactions
                 .values()) {
+
+            ConfigTransactionControllerInternal configTransactionController = configTransactionControllerEntry.getKey();
             try {
+                configTransactionControllerEntry.getValue().close();
                 configTransactionController.abortConfig();
             } catch (RuntimeException e) {
                 logger.warn("Ignoring exception while aborting {}",
@@ -652,15 +661,16 @@ class TransactionsHolder {
      * every time current transactions are requested.
      */
     @GuardedBy("ConfigRegistryImpl.this")
-    private final Map<String /* transactionName */, ConfigTransactionControllerInternal> transactions = new HashMap<>();
+    private final Map<String /* transactionName */,
+            Entry<ConfigTransactionControllerInternal, ConfigTransactionLookupRegistry>> transactions = new HashMap<>();
 
     /**
      * Can only be called from within synchronized method.
      */
     public void add(String transactionName,
-                    ConfigTransactionControllerInternal transactionController) {
+                    ConfigTransactionControllerInternal transactionController, ConfigTransactionLookupRegistry txLookupRegistry) {
         Object oldValue = transactions.put(transactionName,
-                transactionController);
+                Maps.immutableEntry(transactionController, txLookupRegistry));
         if (oldValue != null) {
             throw new IllegalStateException(
                     "Error: two transactions with same name");
@@ -674,13 +684,13 @@ class TransactionsHolder {
      *
      * @return current view on transactions map.
      */
-    public Map<String, ConfigTransactionControllerInternal> getCurrentTransactions() {
+    public Map<String, Entry<ConfigTransactionControllerInternal, ConfigTransactionLookupRegistry>> getCurrentTransactions() {
         // first, remove closed transaction
-        for (Iterator<Entry<String, ConfigTransactionControllerInternal>> it = transactions
+        for (Iterator<Entry<String, Entry<ConfigTransactionControllerInternal, ConfigTransactionLookupRegistry>>> it = transactions
                 .entrySet().iterator(); it.hasNext(); ) {
-            Entry<String, ConfigTransactionControllerInternal> entry = it
+            Entry<String, Entry<ConfigTransactionControllerInternal, ConfigTransactionLookupRegistry>> entry = it
                     .next();
-            if (entry.getValue().isClosed()) {
+            if (entry.getValue().getKey().isClosed()) {
                 it.remove();
             }
         }
index f7afded51ff0c81468b0678c0b964485cd1b0b8c..84f76c993692055899f7aea55a477c44c970f576 100644 (file)
@@ -13,6 +13,7 @@ import org.opendaylight.controller.config.api.ServiceReferenceWritableRegistry;
 import org.opendaylight.controller.config.api.ValidationException;
 import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
 import org.opendaylight.controller.config.manager.impl.dependencyresolver.DependencyResolverManager;
+import org.opendaylight.controller.config.manager.impl.dependencyresolver.ModuleInternalTransactionalInfo;
 import org.opendaylight.controller.config.manager.impl.dynamicmbean.DynamicWritableWrapper;
 import org.opendaylight.controller.config.manager.impl.dynamicmbean.ReadOnlyAtomicBoolean;
 import org.opendaylight.controller.config.manager.impl.dynamicmbean.ReadOnlyAtomicBoolean.ReadOnlyAtomicBooleanImpl;
@@ -95,7 +96,8 @@ class ConfigTransactionControllerImpl implements
         this.currentlyRegisteredFactories = currentlyRegisteredFactories;
         this.factoriesHolder = new HierarchicalConfigMBeanFactoriesHolder(currentlyRegisteredFactories);
         this.transactionStatus = new TransactionStatus();
-        this.dependencyResolverManager = new DependencyResolverManager(transactionName, transactionStatus, writableSRRegistry, codecRegistry);
+        this.dependencyResolverManager = new DependencyResolverManager(txLookupRegistry.getTransactionIdentifier(),
+                transactionStatus, writableSRRegistry, codecRegistry);
         this.transactionsMBeanServer = transactionsMBeanServer;
         this.configMBeanServer = configMBeanServer;
         this.blankTransaction = blankTransaction;
@@ -231,11 +233,10 @@ class ConfigTransactionControllerImpl implements
         // put wrapper to jmx
         TransactionModuleJMXRegistration transactionModuleJMXRegistration = getTxModuleJMXRegistrator()
                 .registerMBean(writableDynamicWrapper, writableON);
-        ModuleInternalTransactionalInfo moduleInternalTransactionalInfo = new ModuleInternalTransactionalInfo(
+
+        dependencyResolverManager.put(
                 moduleIdentifier, module, moduleFactory,
                 maybeOldConfigBeanInfo, transactionModuleJMXRegistration, isDefaultBean);
-
-        dependencyResolverManager.put(moduleInternalTransactionalInfo);
         return writableON;
     }
 
@@ -394,8 +395,6 @@ class ConfigTransactionControllerImpl implements
 
         logger.trace("Committed configuration {}", getTransactionIdentifier());
         transactionStatus.setCommitted();
-        // unregister this and all modules from jmx
-        close();
 
         return dependencyResolverManager.getSortedModuleIdentifiers();
     }
@@ -413,8 +412,7 @@ class ConfigTransactionControllerImpl implements
     }
 
     public void close() {
-        //FIXME: should not close object that was retrieved in constructor, a wrapper object should do that perhaps
-        txLookupRegistry.close();
+        dependencyResolverManager.close();
     }
 
     @Override
@@ -572,6 +570,7 @@ class ConfigTransactionControllerImpl implements
         return writableSRRegistry;
     }
 
+    @Override
     public TransactionIdentifier getTransactionIdentifier() {
         return txLookupRegistry.getTransactionIdentifier();
     }
index 82bae44a01b60148b9105e4e8ef98cc1530daf9f..f6164e32561d7ad5688abde93ac6cb4bc96cbec1 100644 (file)
@@ -23,7 +23,7 @@ import org.osgi.framework.BundleContext;
  * and {@link ConfigRegistryImpl} (consumer).
  */
 interface ConfigTransactionControllerInternal extends
-        ConfigTransactionControllerImplMXBean {
+        ConfigTransactionControllerImplMXBean, AutoCloseable {
 
 
 
@@ -75,4 +75,8 @@ interface ConfigTransactionControllerInternal extends
 
     ServiceReferenceWritableRegistry getWritableRegistry();
 
+    TransactionIdentifier getTransactionIdentifier();
+
+    @Override
+    void close();
 }
diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/DeadlockMonitor.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/DeadlockMonitor.java
new file mode 100644 (file)
index 0000000..ba7ab7f
--- /dev/null
@@ -0,0 +1,122 @@
+package org.opendaylight.controller.config.manager.impl;
+
+import org.opendaylight.controller.config.api.ModuleIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.annotation.Nullable;
+import javax.annotation.concurrent.GuardedBy;
+import java.util.concurrent.TimeUnit;
+
+public class DeadlockMonitor implements AutoCloseable {
+    private static final Logger logger = LoggerFactory.getLogger(DeadlockMonitorRunnable.class);
+
+    private static final long WARN_AFTER_MILLIS = 5000;
+
+    private final TransactionIdentifier transactionIdentifier;
+    private final DeadlockMonitorRunnable thread;
+    @GuardedBy("this")
+    private ModuleIdentifierWithNanos moduleIdentifierWithNanos = new ModuleIdentifierWithNanos();
+
+    public DeadlockMonitor(TransactionIdentifier transactionIdentifier) {
+        this.transactionIdentifier = transactionIdentifier;
+        thread = new DeadlockMonitorRunnable();
+        thread.start();
+    }
+
+    public synchronized void setCurrentlyInstantiatedModule(ModuleIdentifier currentlyInstantiatedModule) {
+        this.moduleIdentifierWithNanos = new ModuleIdentifierWithNanos(currentlyInstantiatedModule);
+    }
+
+    public boolean isAlive() {
+        return thread.isAlive();
+    }
+
+    @Override
+    public void close() {
+        thread.interrupt();
+    }
+
+    @Override
+    public String toString() {
+        return "DeadlockMonitor{" + transactionIdentifier + '}';
+    }
+
+    private class DeadlockMonitorRunnable extends Thread {
+
+        private DeadlockMonitorRunnable() {
+            super(DeadlockMonitor.this.toString());
+        }
+
+        @Override
+        public void run() {
+            ModuleIdentifierWithNanos old = new ModuleIdentifierWithNanos(); // null moduleId
+            while (this.isInterrupted() == false) {
+                ModuleIdentifierWithNanos copy = new ModuleIdentifierWithNanos(DeadlockMonitor.this.moduleIdentifierWithNanos);
+                if (old.moduleIdentifier == null) {
+                    // started
+                    old = copy;
+                } else if (old.moduleIdentifier != null && old.equals(copy)) {
+                    // is the getInstance() running longer than WARN_AFTER_MILLIS ?
+                    long runningTime = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - copy.nanoTime);
+                    if (runningTime > WARN_AFTER_MILLIS) {
+                        logger.warn("{} did not finish after {} ms", copy.moduleIdentifier, runningTime);
+                    }
+                }
+                try {
+                    sleep(1000);
+                } catch (InterruptedException e) {
+                    interrupt();
+                }
+            }
+            logger.trace("Exiting {}", this);
+        }
+
+        @Override
+        public String toString() {
+            return "DeadLockMonitorRunnable{" + transactionIdentifier + "}";
+        }
+    }
+
+    private class ModuleIdentifierWithNanos {
+        @Nullable
+        private final ModuleIdentifier moduleIdentifier;
+        private final long nanoTime;
+
+        private ModuleIdentifierWithNanos() {
+            moduleIdentifier = null;
+            nanoTime = System.nanoTime();
+        }
+
+        private ModuleIdentifierWithNanos(ModuleIdentifier moduleIdentifier) {
+            this.moduleIdentifier = moduleIdentifier;
+            nanoTime = System.nanoTime();
+        }
+
+        private ModuleIdentifierWithNanos(ModuleIdentifierWithNanos copy) {
+            moduleIdentifier = copy.moduleIdentifier;
+            nanoTime = copy.nanoTime;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) return true;
+            if (o == null || getClass() != o.getClass()) return false;
+
+            ModuleIdentifierWithNanos that = (ModuleIdentifierWithNanos) o;
+
+            if (nanoTime != that.nanoTime) return false;
+            if (moduleIdentifier != null ? !moduleIdentifier.equals(that.moduleIdentifier) : that.moduleIdentifier != null)
+                return false;
+
+            return true;
+        }
+
+        @Override
+        public int hashCode() {
+            int result = moduleIdentifier != null ? moduleIdentifier.hashCode() : 0;
+            result = 31 * result + (int) (nanoTime ^ (nanoTime >>> 32));
+            return result;
+        }
+    }
+}
index 941aec10969fd90c700d257579b02c88520e40e9..fd6262cb8cf34f222b70c0e643bf9edc688d46b5 100644 (file)
@@ -10,6 +10,7 @@ package org.opendaylight.controller.config.manager.impl;
 import javax.annotation.Nullable;
 
 import org.opendaylight.controller.config.api.ModuleIdentifier;
+import org.opendaylight.controller.config.manager.impl.dependencyresolver.DestroyedModule;
 import org.opendaylight.controller.config.manager.impl.dynamicmbean.DynamicReadableWrapper;
 import org.opendaylight.controller.config.manager.impl.jmx.ModuleJMXRegistrator;
 import org.opendaylight.controller.config.manager.impl.jmx.RootRuntimeBeanRegistratorImpl;
index e3057a1179419bf6c42daafee1f48bbbd131e786..c229450c30138584e615e552843c1b0f10581dca 100644 (file)
@@ -118,7 +118,7 @@ final class DependencyResolverImpl implements DependencyResolver,
         }
     }
 
-    // transalate from serviceref to module ON
+    // translate from serviceref to module ON
     private ObjectName translateServiceRefIfPossible(ObjectName dependentReadOnlyON) {
         if (ObjectNameUtil.isServiceReference(dependentReadOnlyON)) {
             String serviceQName = ObjectNameUtil.getServiceQName(dependentReadOnlyON);
@@ -214,7 +214,7 @@ final class DependencyResolverImpl implements DependencyResolver,
         return maxDependencyDepth;
     }
 
-    public void countMaxDependencyDepth(DependencyResolverManager manager) {
+    void countMaxDependencyDepth(DependencyResolverManager manager) {
         transactionStatus.checkCommitted();
         if (maxDependencyDepth == null) {
             maxDependencyDepth = getMaxDepth(this, manager,
@@ -257,4 +257,5 @@ final class DependencyResolverImpl implements DependencyResolver,
     public ModuleIdentifier getIdentifier() {
         return name;
     }
+
 }
index c115934d370dc29b4c80dbe18dc33fb75ed6c5c9..b99bf8330e5be412a6965ff78ccad4bb4b520c14 100644 (file)
@@ -7,45 +7,57 @@
  */
 package org.opendaylight.controller.config.manager.impl.dependencyresolver;
 
+import com.google.common.reflect.AbstractInvocationHandler;
+import com.google.common.reflect.Reflection;
 import org.opendaylight.controller.config.api.DependencyResolver;
 import org.opendaylight.controller.config.api.DependencyResolverFactory;
 import org.opendaylight.controller.config.api.JmxAttribute;
 import org.opendaylight.controller.config.api.ModuleIdentifier;
+import org.opendaylight.controller.config.api.RuntimeBeanRegistratorAwareModule;
 import org.opendaylight.controller.config.api.ServiceReferenceReadableRegistry;
 import org.opendaylight.controller.config.manager.impl.CommitInfo;
-import org.opendaylight.controller.config.manager.impl.ModuleInternalTransactionalInfo;
+import org.opendaylight.controller.config.manager.impl.DeadlockMonitor;
+import org.opendaylight.controller.config.manager.impl.ModuleInternalInfo;
+import org.opendaylight.controller.config.manager.impl.TransactionIdentifier;
 import org.opendaylight.controller.config.manager.impl.TransactionStatus;
+import org.opendaylight.controller.config.manager.impl.jmx.TransactionModuleJMXRegistrator.TransactionModuleJMXRegistration;
 import org.opendaylight.controller.config.spi.Module;
 import org.opendaylight.controller.config.spi.ModuleFactory;
 import org.opendaylight.yangtools.yang.data.impl.codec.CodecRegistry;
 
 import javax.annotation.concurrent.GuardedBy;
 import javax.management.InstanceAlreadyExistsException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
+import static com.google.common.base.Preconditions.checkState;
+
 /**
  * Holds information about modules being created and destroyed within this
  * transaction. Observes usage of DependencyResolver within modules to figure
  * out dependency tree.
  */
-public class DependencyResolverManager implements TransactionHolder, DependencyResolverFactory {
+public class DependencyResolverManager implements DependencyResolverFactory, AutoCloseable {
     @GuardedBy("this")
     private final Map<ModuleIdentifier, DependencyResolverImpl> moduleIdentifiersToDependencyResolverMap = new HashMap<>();
     private final ModulesHolder modulesHolder;
     private final TransactionStatus transactionStatus;
     private final ServiceReferenceReadableRegistry readableRegistry;
     private final CodecRegistry codecRegistry;
+    private final DeadlockMonitor deadlockMonitor;
 
-    public DependencyResolverManager(String transactionName,
+    public DependencyResolverManager(TransactionIdentifier transactionIdentifier,
                                      TransactionStatus transactionStatus, ServiceReferenceReadableRegistry readableRegistry, CodecRegistry codecRegistry) {
-        this.modulesHolder = new ModulesHolder(transactionName);
+        this.modulesHolder = new ModulesHolder(transactionIdentifier);
         this.transactionStatus = transactionStatus;
         this.readableRegistry = readableRegistry;
         this.codecRegistry = codecRegistry;
+        this.deadlockMonitor = new DeadlockMonitor(transactionIdentifier);
     }
 
     @Override
@@ -88,7 +100,6 @@ public class DependencyResolverManager implements TransactionHolder, DependencyR
         return result;
     }
 
-    @Override
     public ModuleInternalTransactionalInfo destroyModule(
             ModuleIdentifier moduleIdentifier) {
         transactionStatus.checkNotCommitted();
@@ -99,45 +110,85 @@ public class DependencyResolverManager implements TransactionHolder, DependencyR
     }
 
     // protect write access
-    @Override
+
     public void put(
-            ModuleInternalTransactionalInfo moduleInternalTransactionalInfo) {
+            final ModuleIdentifier moduleIdentifier,
+            final Module module,
+            ModuleFactory moduleFactory,
+            ModuleInternalInfo maybeOldInternalInfo,
+            TransactionModuleJMXRegistration transactionModuleJMXRegistration,
+            boolean isDefaultBean) {
         transactionStatus.checkNotCommitted();
+
+        Class<? extends Module> moduleClass = Module.class;
+        if (module instanceof RuntimeBeanRegistratorAwareModule) {
+            moduleClass = RuntimeBeanRegistratorAwareModule.class;
+        }
+        Module proxiedModule = Reflection.newProxy(moduleClass, new AbstractInvocationHandler() {
+            // optimization: subsequent calls to getInstance MUST return the same value during transaction,
+            // so it is safe to cache the response
+            private Object cachedInstance;
+
+            @Override
+            protected Object handleInvocation(Object proxy, Method method, Object[] args) throws Throwable {
+                boolean isGetInstance = method.getName().equals("getInstance");
+                if (isGetInstance) {
+                    if (cachedInstance != null) {
+                        return cachedInstance;
+                    }
+
+                    checkState(deadlockMonitor.isAlive(), "Deadlock monitor is not alive");
+                    deadlockMonitor.setCurrentlyInstantiatedModule(moduleIdentifier);
+                }
+                try {
+                    Object response = method.invoke(module, args);
+                    if (isGetInstance) {
+                        cachedInstance = response;
+                    }
+                    return response;
+                } catch(InvocationTargetException e) {
+                    throw e.getCause();
+                } finally {
+                    if (isGetInstance) {
+                        deadlockMonitor.setCurrentlyInstantiatedModule(null);
+                    }
+                }
+            }
+        });
+
+
+        ModuleInternalTransactionalInfo moduleInternalTransactionalInfo = new ModuleInternalTransactionalInfo(
+                moduleIdentifier, proxiedModule, moduleFactory,
+                maybeOldInternalInfo, transactionModuleJMXRegistration, isDefaultBean, module);
         modulesHolder.put(moduleInternalTransactionalInfo);
     }
 
     // wrapped methods:
 
-    @Override
     public CommitInfo toCommitInfo() {
         return modulesHolder.toCommitInfo();
     }
 
-    @Override
     public Module findModule(ModuleIdentifier moduleIdentifier,
-            JmxAttribute jmxAttributeForReporting) {
+                             JmxAttribute jmxAttributeForReporting) {
         return modulesHolder.findModule(moduleIdentifier,
                 jmxAttributeForReporting);
     }
 
-    @Override
     public ModuleInternalTransactionalInfo findModuleInternalTransactionalInfo(ModuleIdentifier moduleIdentifier) {
         return modulesHolder.findModuleInternalTransactionalInfo(moduleIdentifier);
     }
 
-    @Override
     public ModuleFactory findModuleFactory(ModuleIdentifier moduleIdentifier,
-            JmxAttribute jmxAttributeForReporting) {
+                                           JmxAttribute jmxAttributeForReporting) {
         return modulesHolder.findModuleFactory(moduleIdentifier,
                 jmxAttributeForReporting);
     }
 
-    @Override
     public Map<ModuleIdentifier, Module> getAllModules() {
         return modulesHolder.getAllModules();
     }
 
-    @Override
     public void assertNotExists(ModuleIdentifier moduleIdentifier)
             throws InstanceAlreadyExistsException {
         modulesHolder.assertNotExists(moduleIdentifier);
@@ -145,11 +196,16 @@ public class DependencyResolverManager implements TransactionHolder, DependencyR
 
     public List<ModuleIdentifier> findAllByFactory(ModuleFactory factory) {
         List<ModuleIdentifier> result = new ArrayList<>();
-        for( ModuleInternalTransactionalInfo  info : modulesHolder.getAllInfos()) {
+        for (ModuleInternalTransactionalInfo info : modulesHolder.getAllInfos()) {
             if (factory.equals(info.getModuleFactory())) {
                 result.add(info.getIdentifier());
             }
         }
         return result;
     }
+
+    public void close() {
+        deadlockMonitor.close();
+    }
+
 }
@@ -5,7 +5,7 @@
  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
  * and is available at http://www.eclipse.org/legal/epl-v10.html
  */
-package org.opendaylight.controller.config.manager.impl;
+package org.opendaylight.controller.config.manager.impl.dependencyresolver;
 
 import org.opendaylight.controller.config.api.ModuleIdentifier;
 import org.opendaylight.controller.config.manager.impl.jmx.ModuleJMXRegistrator;
@@ -31,7 +31,7 @@ public class DestroyedModule implements AutoCloseable,
     private final OsgiRegistration osgiRegistration;
     private final int orderingIdx;
 
-    DestroyedModule(ModuleIdentifier identifier, AutoCloseable instance,
+    public DestroyedModule(ModuleIdentifier identifier, AutoCloseable instance,
             ModuleJMXRegistrator oldJMXRegistrator,
             OsgiRegistration osgiRegistration, int orderingIdx) {
         this.identifier = identifier;
@@ -5,9 +5,10 @@
  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
  * and is available at http://www.eclipse.org/legal/epl-v10.html
  */
-package org.opendaylight.controller.config.manager.impl;
+package org.opendaylight.controller.config.manager.impl.dependencyresolver;
 
 import org.opendaylight.controller.config.api.ModuleIdentifier;
+import org.opendaylight.controller.config.manager.impl.ModuleInternalInfo;
 import org.opendaylight.controller.config.manager.impl.dynamicmbean.DynamicReadableWrapper;
 import org.opendaylight.controller.config.manager.impl.jmx.TransactionModuleJMXRegistrator.TransactionModuleJMXRegistration;
 import org.opendaylight.controller.config.spi.Module;
@@ -18,24 +19,25 @@ import javax.annotation.Nullable;
 
 public class ModuleInternalTransactionalInfo implements Identifiable<ModuleIdentifier> {
     private final ModuleIdentifier name;
-    private final Module module;
+    private final Module proxiedModule, realModule;
     private final ModuleFactory moduleFactory;
     @Nullable
     private final ModuleInternalInfo maybeOldInternalInfo;
     private final TransactionModuleJMXRegistration transactionModuleJMXRegistration;
     private final boolean isDefaultBean;
 
-    ModuleInternalTransactionalInfo(ModuleIdentifier name, Module module,
-                                    ModuleFactory moduleFactory,
-                                    ModuleInternalInfo maybeOldInternalInfo,
-                                    TransactionModuleJMXRegistration transactionModuleJMXRegistration,
-                                    boolean isDefaultBean) {
+    public ModuleInternalTransactionalInfo(ModuleIdentifier name, Module proxiedModule,
+                                           ModuleFactory moduleFactory,
+                                           ModuleInternalInfo maybeOldInternalInfo,
+                                           TransactionModuleJMXRegistration transactionModuleJMXRegistration,
+                                           boolean isDefaultBean, Module realModule) {
         this.name = name;
-        this.module = module;
+        this.proxiedModule = proxiedModule;
         this.moduleFactory = moduleFactory;
         this.maybeOldInternalInfo = maybeOldInternalInfo;
         this.transactionModuleJMXRegistration = transactionModuleJMXRegistration;
         this.isDefaultBean = isDefaultBean;
+        this.realModule = realModule;
     }
 
 
@@ -56,8 +58,8 @@ public class ModuleInternalTransactionalInfo implements Identifiable<ModuleIdent
     }
 
 
-    public Module getModule() {
-        return module;
+    public Module getProxiedModule() {
+        return proxiedModule;
     }
 
     public ModuleFactory getModuleFactory() {
@@ -84,4 +86,8 @@ public class ModuleInternalTransactionalInfo implements Identifiable<ModuleIdent
     public boolean isDefaultBean() {
         return isDefaultBean;
     }
+
+    public Module getRealModule() {
+        return realModule;
+    }
 }
index 7c7d9f95a4e71899ff5feec39bdb5433ebc6baa6..81cc34ac970f8540943b12cf1d45549329b95e46 100644 (file)
@@ -11,8 +11,7 @@ import org.opendaylight.controller.config.api.JmxAttribute;
 import org.opendaylight.controller.config.api.JmxAttributeValidationException;
 import org.opendaylight.controller.config.api.ModuleIdentifier;
 import org.opendaylight.controller.config.manager.impl.CommitInfo;
-import org.opendaylight.controller.config.manager.impl.DestroyedModule;
-import org.opendaylight.controller.config.manager.impl.ModuleInternalTransactionalInfo;
+import org.opendaylight.controller.config.manager.impl.TransactionIdentifier;
 import org.opendaylight.controller.config.spi.Module;
 import org.opendaylight.controller.config.spi.ModuleFactory;
 
@@ -30,19 +29,19 @@ import java.util.Set;
 /**
  * Represents modules to be committed.
  */
-class ModulesHolder implements TransactionHolder {
-    private final String transactionName;
+class ModulesHolder {
+    private final TransactionIdentifier transactionIdentifier;
     @GuardedBy("this")
     private final Map<ModuleIdentifier, ModuleInternalTransactionalInfo> commitMap = new HashMap<>();
 
     @GuardedBy("this")
     private final Set<ModuleInternalTransactionalInfo> unorderedDestroyedFromPreviousTransactions = new HashSet<>();
 
-    ModulesHolder(String transactionName) {
-        this.transactionName = transactionName;
+    ModulesHolder(TransactionIdentifier transactionIdentifier) {
+        this.transactionIdentifier = transactionIdentifier;
     }
 
-    @Override
+
     public CommitInfo toCommitInfo() {
         List<DestroyedModule> orderedDestroyedFromPreviousTransactions = new ArrayList<>(
                 unorderedDestroyedFromPreviousTransactions.size());
@@ -62,43 +61,38 @@ class ModulesHolder implements TransactionHolder {
                 .get(moduleIdentifier);
         JmxAttributeValidationException.checkNotNull(
                 moduleInternalTransactionalInfo, "Module " + moduleIdentifier
-                        + "" + " not found in transaction " + transactionName,
+                        + "" + " not found in transaction " + transactionIdentifier,
                 jmxAttributeForReporting);
         return moduleInternalTransactionalInfo;
     }
 
-    @Override
     public Module findModule(ModuleIdentifier moduleIdentifier,
             JmxAttribute jmxAttributeForReporting) {
         return findModuleInternalTransactionalInfo(moduleIdentifier,
-                jmxAttributeForReporting).getModule();
+                jmxAttributeForReporting).getProxiedModule();
     }
 
-    @Override
     public ModuleFactory findModuleFactory(ModuleIdentifier moduleIdentifier,
             JmxAttribute jmxAttributeForReporting) {
         return findModuleInternalTransactionalInfo(moduleIdentifier,
                 jmxAttributeForReporting).getModuleFactory();
     }
 
-    @Override
     public Map<ModuleIdentifier, Module> getAllModules() {
         Map<ModuleIdentifier, Module> result = new HashMap<>();
         for (ModuleInternalTransactionalInfo entry : commitMap.values()) {
             ModuleIdentifier name = entry.getIdentifier();
-            result.put(name, entry.getModule());
+            result.put(name, entry.getProxiedModule());
         }
         return result;
     }
 
-    @Override
     public void put(
             ModuleInternalTransactionalInfo moduleInternalTransactionalInfo) {
         commitMap.put(moduleInternalTransactionalInfo.getIdentifier(),
                 moduleInternalTransactionalInfo);
     }
 
-    @Override
     public ModuleInternalTransactionalInfo destroyModule(
             ModuleIdentifier moduleIdentifier) {
         ModuleInternalTransactionalInfo found = commitMap.remove(moduleIdentifier);
@@ -111,7 +105,6 @@ class ModulesHolder implements TransactionHolder {
         return found;
     }
 
-    @Override
     public void assertNotExists(ModuleIdentifier moduleIdentifier)
             throws InstanceAlreadyExistsException {
         if (commitMap.containsKey(moduleIdentifier)) {
@@ -124,7 +117,6 @@ class ModulesHolder implements TransactionHolder {
         return commitMap.values();
     }
 
-    @Override
     public ModuleInternalTransactionalInfo findModuleInternalTransactionalInfo(ModuleIdentifier moduleIdentifier) {
         ModuleInternalTransactionalInfo found = commitMap.get(moduleIdentifier);
         if (found == null) {
diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dependencyresolver/TransactionHolder.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/dependencyresolver/TransactionHolder.java
deleted file mode 100644 (file)
index bccd453..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.config.manager.impl.dependencyresolver;
-
-import org.opendaylight.controller.config.api.JmxAttribute;
-import org.opendaylight.controller.config.api.ModuleIdentifier;
-import org.opendaylight.controller.config.manager.impl.CommitInfo;
-import org.opendaylight.controller.config.manager.impl.ModuleInternalTransactionalInfo;
-import org.opendaylight.controller.config.spi.Module;
-import org.opendaylight.controller.config.spi.ModuleFactory;
-
-import javax.management.InstanceAlreadyExistsException;
-import java.util.Map;
-
-interface TransactionHolder {
-    CommitInfo toCommitInfo();
-
-    Module findModule(ModuleIdentifier moduleIdentifier,
-            JmxAttribute jmxAttributeForReporting);
-
-    ModuleFactory findModuleFactory(ModuleIdentifier moduleIdentifier,
-            JmxAttribute jmxAttributeForReporting);
-
-    Map<ModuleIdentifier, Module> getAllModules();
-
-    void put(ModuleInternalTransactionalInfo moduleInternalTransactionalInfo);
-
-    ModuleInternalTransactionalInfo destroyModule(
-            ModuleIdentifier moduleIdentifier);
-
-    void assertNotExists(ModuleIdentifier moduleIdentifier)
-            throws InstanceAlreadyExistsException;
-
-    ModuleInternalTransactionalInfo findModuleInternalTransactionalInfo(ModuleIdentifier moduleIdentifier);
-
-}
index 8ba290f30632e10101cc2185367844d29ee73f19..a8fdfda7d7201f9cb00f50f590265e64825d2751 100644 (file)
@@ -20,7 +20,6 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.io.InputStream;
-import java.lang.reflect.InvocationTargetException;
 import java.net.URL;
 import java.util.Collection;
 import java.util.LinkedList;
@@ -98,31 +97,26 @@ public final class ModuleInfoBundleTracker implements BundleTrackerCustomizer<Co
             errorMessage = logMessage("Class {} does not implement {} in bundle {}", clazz, YangModelBindingProvider.class, bundle);
             throw new IllegalStateException(errorMessage);
         }
-
+        YangModelBindingProvider instance;
         try {
-            Object instance = clazz.newInstance();
-            Object result = clazz.getMethod(GET_MODULE_INFO_METHOD).invoke(instance);
-
-            if (YangModuleInfo.class.isAssignableFrom(result.getClass()) == false) {
-                errorMessage = logMessage("Error invoking method not found {} in bundle {}, reason {}",
-                        GET_MODULE_INFO_METHOD, bundle, "Not assignable from " + YangModuleInfo.class);
-            } else {
-                return (YangModuleInfo) result;
-            }
-
+            Object instanceObj = clazz.newInstance();
+            instance = YangModelBindingProvider.class.cast(instanceObj);
         } catch (InstantiationException e) {
             errorMessage = logMessage("Could not instantiate {} in bundle {}, reason {}", moduleInfoClass, bundle, e);
+            throw new IllegalStateException(errorMessage, e);
         } catch (IllegalAccessException e) {
             errorMessage = logMessage("Illegal access during instatiation of class {} in bundle {}, reason {}",
                     moduleInfoClass, bundle, e);
-        } catch (NoSuchMethodException e) {
-            errorMessage = logMessage("Method not found {} in bundle {}, reason {}", GET_MODULE_INFO_METHOD, bundle, e);
-        } catch (InvocationTargetException e) {
-            errorMessage = logMessage("Error invoking method {} in bundle {}, reason {}", GET_MODULE_INFO_METHOD,
-                    bundle, e);
+            throw new IllegalStateException(errorMessage, e);
         }
+        try{
+            return instance.getModuleInfo();
+        } catch (NoClassDefFoundError e) {
 
-        throw new IllegalStateException(errorMessage);
+
+            logger.error("Error while executing getModuleInfo on {}", instance, e);
+            throw e;
+        }
     }
 
     private static Class<?> loadClass(String moduleInfoClass, Bundle bundle) {
index 63a66e96eb152c1dfe37caf592f2d0d4778e52c6..123e52f6759e2ec9321c81aa36c6e655ddcb9c7f 100644 (file)
@@ -7,24 +7,27 @@
  */
 package org.opendaylight.controller.config.manager.impl.dependencyresolver;
 
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.reset;
-
-import java.util.Arrays;
-import java.util.List;
-
 import org.junit.Before;
 import org.junit.Test;
 import org.opendaylight.controller.config.api.JmxAttribute;
 import org.opendaylight.controller.config.api.ModuleIdentifier;
 import org.opendaylight.controller.config.api.ServiceReferenceReadableRegistry;
 import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
-import org.opendaylight.controller.config.manager.impl.ModuleInternalTransactionalInfo;
+import org.opendaylight.controller.config.manager.impl.ModuleInternalInfo;
+import org.opendaylight.controller.config.manager.impl.TransactionIdentifier;
 import org.opendaylight.controller.config.manager.impl.TransactionStatus;
+import org.opendaylight.controller.config.manager.impl.jmx.TransactionModuleJMXRegistrator.TransactionModuleJMXRegistration;
 import org.opendaylight.controller.config.spi.Module;
+import org.opendaylight.controller.config.spi.ModuleFactory;
+
+import java.util.Arrays;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.reset;
 
 public class DependencyResolverManagerTest {
 
@@ -42,7 +45,7 @@ public class DependencyResolverManagerTest {
     public void setUp() {
         transactionStatus = mock(TransactionStatus.class);
         ServiceReferenceReadableRegistry mockedRegistry = mock(ServiceReferenceReadableRegistry.class);
-        tested = new DependencyResolverManager("txName", transactionStatus, mockedRegistry, null);
+        tested = new DependencyResolverManager(new TransactionIdentifier("txName"), transactionStatus, mockedRegistry, null);
         doNothing().when(transactionStatus).checkCommitStarted();
         doNothing().when(transactionStatus).checkNotCommitted();
     }
@@ -87,10 +90,18 @@ public class DependencyResolverManagerTest {
 
     private static void mockGetInstance(DependencyResolverManager tested,
             ModuleIdentifier moduleIdentifier) {
-        ModuleInternalTransactionalInfo mock = mock(ModuleInternalTransactionalInfo.class);
-        doReturn(moduleIdentifier).when(mock).getIdentifier();
-        doReturn(mockedModule()).when(mock).getModule();
-        tested.put(mock);
+
+        ModuleFactory moduleFactory = mock(ModuleFactory.class);
+        ModuleInternalInfo maybeOldInternalInfo = null;
+        TransactionModuleJMXRegistration transactionModuleJMXRegistration = null;
+        boolean isDefaultBean = false;
+
+        tested.put(moduleIdentifier,
+        mockedModule(),
+         moduleFactory,
+         maybeOldInternalInfo,
+         transactionModuleJMXRegistration,
+         isDefaultBean);
     }
 
     private static Module mockedModule() {
index f4ba5ef887e359b9e5a6ab324ac58cc359ae565f..df6dce124339991a50c0016d30dd87cc76168e88 100644 (file)
@@ -7,15 +7,7 @@
  */
 package org.opendaylight.controller.config.manager.testingservices.parallelapsp;
 
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.base.Preconditions.checkState;
-
-import java.io.Closeable;
-
-import javax.annotation.Nullable;
-import javax.annotation.concurrent.NotThreadSafe;
-import javax.management.ObjectName;
-
+import com.google.common.base.Strings;
 import org.opendaylight.controller.config.api.DependencyResolver;
 import org.opendaylight.controller.config.api.JmxAttribute;
 import org.opendaylight.controller.config.api.ModuleIdentifier;
@@ -26,7 +18,13 @@ import org.opendaylight.controller.config.spi.Module;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.google.common.base.Strings;
+import javax.annotation.Nullable;
+import javax.annotation.concurrent.NotThreadSafe;
+import javax.management.ObjectName;
+import java.io.Closeable;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
 
 /**
  * Represents service that has dependency to thread pool.
index 4e9ce009b420ad05b4c697144fd215c310cca6db..28408abed2fb564c05688302cc0d3b20be0465a9 100644 (file)
@@ -326,7 +326,7 @@ public class SimpleConfigurationTest extends AbstractConfigTest {
     }
 
     @Test
-    public void testAbort() {
+    public void testAbort() throws InstanceAlreadyExistsException, ValidationException {
         ConfigTransactionJMXClient transaction = configRegistryClient
                 .createTransaction();
         assertEquals(1, configRegistryClient.getOpenConfigs().size());
@@ -336,14 +336,14 @@ public class SimpleConfigurationTest extends AbstractConfigTest {
             transaction.createModule(TestingFixedThreadPoolModuleFactory.NAME,
                     fixed1);
             fail();
-        } catch (Exception e) {
-            assertTrue(e.getCause() instanceof InstanceNotFoundException);
+        } catch (IllegalStateException e) {
+            assertEquals("Configuration was aborted", e.getMessage());
         }
         try {
             transaction.validateConfig();
             fail();
-        } catch (Exception e) {
-            assertTrue(e.getCause() instanceof InstanceNotFoundException);
+        } catch (IllegalStateException e) {
+            assertEquals("Configuration was aborted", e.getMessage());
         }
         assertEquals(0, configRegistryClient.getOpenConfigs().size());
     }
diff --git a/opendaylight/config/netty-event-executor-config/src/main/java/org/opendaylight/controller/config/yang/netty/eventexecutor/AutoCloseableEventExecutor.java b/opendaylight/config/netty-event-executor-config/src/main/java/org/opendaylight/controller/config/yang/netty/eventexecutor/AutoCloseableEventExecutor.java
new file mode 100644 (file)
index 0000000..69ea51f
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.config.yang.netty.eventexecutor;
+
+import com.google.common.reflect.AbstractInvocationHandler;
+import com.google.common.reflect.Reflection;
+import io.netty.util.concurrent.EventExecutor;
+
+import java.lang.reflect.Method;
+import java.util.concurrent.TimeUnit;
+
+public interface AutoCloseableEventExecutor extends EventExecutor, AutoCloseable {
+
+
+    public static class CloseableEventExecutorMixin implements AutoCloseable {
+        public static final int DEFAULT_SHUTDOWN_SECONDS = 1;
+        private final EventExecutor eventExecutor;
+
+        public CloseableEventExecutorMixin(EventExecutor eventExecutor) {
+            this.eventExecutor = eventExecutor;
+        }
+
+        @Override
+        public void close() {
+            eventExecutor.shutdownGracefully(0, DEFAULT_SHUTDOWN_SECONDS, TimeUnit.SECONDS);
+        }
+
+
+        public static AutoCloseable createCloseableProxy(final EventExecutor eventExecutor) {
+            final CloseableEventExecutorMixin closeableGlobalEventExecutorMixin =
+                    new CloseableEventExecutorMixin(eventExecutor);
+            return Reflection.newProxy(AutoCloseableEventExecutor.class, new AbstractInvocationHandler() {
+                @Override
+                protected Object handleInvocation(Object proxy, Method method, Object[] args) throws Throwable {
+                    if (method.getName().equals("close")) {
+                        closeableGlobalEventExecutorMixin.close();
+                        return null;
+                    } else {
+                        return method.invoke(eventExecutor, args);
+                    }
+                }
+            });
+        }
+
+
+    }
+}
\ No newline at end of file
index 2c4c2117840e89f74e98f1e2ef94e27a56f72424..8751a80b8d163838b08e8b014abc5371be777978 100644 (file)
  */
 package org.opendaylight.controller.config.yang.netty.eventexecutor;
 
-import com.google.common.reflect.AbstractInvocationHandler;
-import com.google.common.reflect.Reflection;
 import io.netty.util.concurrent.EventExecutor;
 import io.netty.util.concurrent.GlobalEventExecutor;
-
-import java.lang.reflect.Method;
-import java.util.concurrent.TimeUnit;
+import org.opendaylight.controller.config.yang.netty.eventexecutor.AutoCloseableEventExecutor.CloseableEventExecutorMixin;
 
 public final class GlobalEventExecutorModule extends
         org.opendaylight.controller.config.yang.netty.eventexecutor.AbstractGlobalEventExecutorModule {
@@ -46,35 +42,10 @@ public final class GlobalEventExecutorModule extends
 
     @Override
     public java.lang.AutoCloseable createInstance() {
-        final CloseableGlobalEventExecutorMixin closeableGlobalEventExecutorMixin =
-                new CloseableGlobalEventExecutorMixin(GlobalEventExecutor.INSTANCE);
-        return Reflection.newProxy(AutoCloseableEventExecutor.class, new AbstractInvocationHandler() {
-            @Override
-            protected Object handleInvocation(Object proxy, Method method, Object[] args) throws Throwable {
-                if (method.getName().equals("close")) {
-                    closeableGlobalEventExecutorMixin.close();
-                    return null;
-                } else {
-                    return method.invoke(GlobalEventExecutor.INSTANCE, args);
-                }
-            }
-        });
+        EventExecutor eventExecutor = GlobalEventExecutor.INSTANCE;
+        return CloseableEventExecutorMixin.createCloseableProxy(eventExecutor);
     }
 
-    public static interface AutoCloseableEventExecutor extends EventExecutor, AutoCloseable {
-
-    }
 
-    public static class CloseableGlobalEventExecutorMixin implements AutoCloseable {
-        private final GlobalEventExecutor eventExecutor;
 
-        public CloseableGlobalEventExecutorMixin(GlobalEventExecutor eventExecutor) {
-            this.eventExecutor = eventExecutor;
-        }
-
-        @Override
-        public void close() {
-            eventExecutor.shutdownGracefully(0, 1, TimeUnit.SECONDS);
-        }
-    }
 }
diff --git a/opendaylight/config/netty-event-executor-config/src/main/java/org/opendaylight/controller/config/yang/netty/eventexecutor/ImmediateEventExecutorModule.java b/opendaylight/config/netty-event-executor-config/src/main/java/org/opendaylight/controller/config/yang/netty/eventexecutor/ImmediateEventExecutorModule.java
new file mode 100644 (file)
index 0000000..27ca63f
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.config.yang.netty.eventexecutor;
+
+import io.netty.util.concurrent.EventExecutor;
+import io.netty.util.concurrent.ImmediateEventExecutor;
+import org.opendaylight.controller.config.yang.netty.eventexecutor.AutoCloseableEventExecutor.CloseableEventExecutorMixin;
+
+public final class ImmediateEventExecutorModule extends org.opendaylight.controller.config.yang.netty.eventexecutor.AbstractImmediateEventExecutorModule {
+
+    public ImmediateEventExecutorModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
+        super(identifier, dependencyResolver);
+    }
+
+    public ImmediateEventExecutorModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver,
+                                        ImmediateEventExecutorModule oldModule, java.lang.AutoCloseable oldInstance) {
+
+        super(identifier, dependencyResolver, oldModule, oldInstance);
+    }
+
+    @Override
+    protected void customValidation() {
+        // Add custom validation for module attributes here.
+    }
+
+    @Override
+    public java.lang.AutoCloseable createInstance() {
+        EventExecutor eventExecutor = ImmediateEventExecutor.INSTANCE;
+        return CloseableEventExecutorMixin.createCloseableProxy(eventExecutor);
+    }
+}
diff --git a/opendaylight/config/netty-event-executor-config/src/main/java/org/opendaylight/controller/config/yang/netty/eventexecutor/ImmediateEventExecutorModuleFactory.java b/opendaylight/config/netty-event-executor-config/src/main/java/org/opendaylight/controller/config/yang/netty/eventexecutor/ImmediateEventExecutorModuleFactory.java
new file mode 100644 (file)
index 0000000..b3ec67b
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.config.yang.netty.eventexecutor;
+
+import org.opendaylight.controller.config.api.DependencyResolver;
+import org.osgi.framework.BundleContext;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+public class ImmediateEventExecutorModuleFactory extends org.opendaylight.controller.config.yang.netty.eventexecutor.AbstractImmediateEventExecutorModuleFactory {
+    public static final String SINGLETON_NAME = "singleton";
+
+    @Override
+    public ImmediateEventExecutorModule instantiateModule(String instanceName, DependencyResolver dependencyResolver, ImmediateEventExecutorModule oldModule, AutoCloseable oldInstance, BundleContext bundleContext) {
+        checkArgument(SINGLETON_NAME.equals(instanceName), "Illegal instance name '" + instanceName + "', only allowed name is " + SINGLETON_NAME);
+        return super.instantiateModule(instanceName, dependencyResolver, oldModule, oldInstance, bundleContext);
+    }
+
+    @Override
+    public ImmediateEventExecutorModule instantiateModule(String instanceName, DependencyResolver dependencyResolver, BundleContext bundleContext) {
+        checkArgument(SINGLETON_NAME.equals(instanceName), "Illegal instance name '" + instanceName + "', only allowed name is " + SINGLETON_NAME);
+        return super.instantiateModule(instanceName, dependencyResolver, bundleContext);
+    }
+}
index e9d1da3f2dd6de1f0c80701a68b21227fadd8c72..8d812adc4d1231f4507c19a70c9d5df4a28e72d0 100644 (file)
@@ -36,7 +36,18 @@ module netty-event-executor {
     augment "/config:modules/config:module/config:configuration" {
         case netty-global-event-executor {
             when "/config:modules/config:module/config:type = 'netty-global-event-executor'";
+        }
+    }
 
+    identity netty-immediate-event-executor {
+        base config:module-type;
+        config:provided-service netty:netty-event-executor;
+        config:java-name-prefix ImmediateEventExecutor;
+    }
+
+    augment "/config:modules/config:module/config:configuration" {
+        case netty-immediate-event-executor {
+            when "/config:modules/config:module/config:type = 'netty-immediate-event-executor'";
         }
     }
 }
index 562db9830197176ae3cd301199ddf13790e3c07f..6cc06ba70502b2e4fed1d315120326cd6552315d 100644 (file)
         <sonar.branch>${user.name}-private-view</sonar.branch>
         <sonar.language>java</sonar.language>
         <exam.version>3.0.0</exam.version>
-        <sal.version>0.7.1-SNAPSHOT</sal.version>
+        <sal.version>0.8.1-SNAPSHOT</sal.version>
     </properties>
 
     <dependencyManagement>
index aa846ff78db2dd4a71ea77087978c559879ec654..65f1ff2fe368ac07255d852e57c58ee2e5e1f610 100644 (file)
@@ -7,24 +7,19 @@
  */
 package org.opendaylight.controller.sal.binding.api.data;
 
-import java.util.concurrent.Future;
-
 import org.opendaylight.controller.md.sal.common.api.data.DataChangePublisher;
 import org.opendaylight.controller.md.sal.common.api.data.DataModificationTransactionFactory;
 import org.opendaylight.controller.md.sal.common.api.data.DataReader;
 import org.opendaylight.controller.sal.binding.api.BindingAwareService;
-import org.opendaylight.controller.sal.common.DataStoreIdentifier;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
 import org.opendaylight.yangtools.yang.binding.DataObject;
-import org.opendaylight.yangtools.yang.binding.DataRoot;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-import org.opendaylight.yangtools.yang.common.RpcResult;
 
 /**
  * DataBrokerService provides unified access to the data stores available in the
  * system.
- * 
- * 
+ *
+ *
  * @see DataProviderService
  */
 public interface DataBrokerService extends //
@@ -32,163 +27,37 @@ public interface DataBrokerService extends //
         DataModificationTransactionFactory<InstanceIdentifier<? extends DataObject>, DataObject>, //
         DataReader<InstanceIdentifier<? extends DataObject>, DataObject>, //
         DataChangePublisher<InstanceIdentifier<? extends DataObject>, DataObject, DataChangeListener> {
-
-    /**
-     * Returns a data from specified Data Store.
-     * 
-     * Returns all the data visible to the consumer from specified Data Store.
-     * 
-     * @param <T>
-     *            Interface generated from YANG module representing root of data
-     * @param store
-     *            Identifier of the store, from which will be data retrieved
-     * @return data visible to the consumer
-     */
-    @Deprecated
-    <T extends DataRoot> T getData(DataStoreIdentifier store, Class<T> rootType);
-
-    /**
-     * Returns a filtered subset of data from specified Data Store.
-     * 
-     * <p>
-     * The filter is modeled as an hierarchy of Java TOs starting with
-     * implementation of {@link DataRoot} representing data root. The semantics
-     * of the filter tree is the same as filter semantics defined in the NETCONF
-     * protocol for rpc operations <code>get</code> and <code>get-config</code>
-     * in Section 6 of RFC6241.
-     * 
-     * 
-     * @see http://tools.ietf.org/html/rfc6241#section-6
-     * @param <T>
-     *            Interface generated from YANG module representing root of data
-     * @param store
-     *            Identifier of the store, from which will be data retrieved
-     * @param filter
-     *            Data tree filter similar to the NETCONF filter
-     * @return
-     */
-    @Deprecated
-    <T extends DataRoot> T getData(DataStoreIdentifier store, T filter);
-
-    /**
-     * Returns a candidate data which are not yet commited.
-     * 
-     * 
-     * @param <T>
-     *            Interface generated from YANG module representing root of data
-     * @param store
-     *            Identifier of the store, from which will be data retrieved
-     * @return
-     */
-    @Deprecated
-    <T extends DataRoot> T getCandidateData(DataStoreIdentifier store, Class<T> rootType);
-
-    /**
-     * Returns a filtered subset of candidate data from specified Data Store.
-     * 
-     * <p>
-     * The filter is modeled as an hierarchy of {@link Node} starting with
-     * {@link CompositeNode} representing data root. The semantics of the filter
-     * tree is the same as filter semantics defined in the NETCONF protocol for
-     * rpc operations <code>get</code> and <code>get-config</code> in Section 6
-     * of RFC6241.
-     * 
-     * 
-     * @see http://tools.ietf.org/html/rfc6241#section-6
-     * @param <T>
-     *            Interface generated from YANG module representing root of data
-     * @param store
-     *            Identifier of the store, from which will be data retrieved
-     * @param filter
-     *            A filter data root
-     * @return
-     */
-    @Deprecated
-    <T extends DataRoot> T getCandidateData(DataStoreIdentifier store, T filter);
-
-    /**
-     * 
-     * @param <T>
-     *            Interface generated from YANG module representing root of data
-     * @param store
-     *            Identifier of the store, in which will be the candidate data
-     *            modified
-     * @param changeSet
-     *            Modification of data tree.
-     * @return Result object containing the modified data tree if the operation
-     *         was successful, otherwise list of the encountered errors.
-     */
-    @Deprecated
-    RpcResult<DataRoot> editCandidateData(DataStoreIdentifier store, DataRoot changeSet);
-
-    /**
-     * Initiates a two-phase commit of candidate data.
-     * 
-     * <p>
-     * The {@link Consumer} could initiate a commit of candidate data
-     * 
-     * <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 {@link Provider} components
-     * of controller. It is assumed that {@link Consumer} has an understanding
-     * of this changes.
-     * 
-     * 
-     * @see DataCommitHandler for further information how two-phase commit is
-     *      processed.
-     * @param store
-     *            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.
-     */
-    @Deprecated
-    Future<RpcResult<Void>> commit(DataStoreIdentifier store);
-
-    @Deprecated
-    DataObject getData(InstanceIdentifier<? extends DataObject> data);
-
-    @Deprecated
-    DataObject getConfigurationData(InstanceIdentifier<?> data);
     /**
      * Creates a data modification transaction.
-     * 
+     *
      * @return new blank data modification transaction.
      */
-    DataModificationTransaction beginTransaction();
-
-    @Deprecated
-    public void registerChangeListener(InstanceIdentifier<? extends DataObject> path, DataChangeListener changeListener);
-
-    @Deprecated
-    public void unregisterChangeListener(InstanceIdentifier<? extends DataObject> path, DataChangeListener changeListener);
+    @Override
+       DataModificationTransaction beginTransaction();
 
     /**
-     * Reads data subtree from configurational store. 
-     * (Store which is populated by consumer, which is usually used to 
+     * Reads data subtree from configurational store.
+     * (Store which is populated by consumer, which is usually used to
      * inject state into providers. E.g. Flow configuration)-
-     * 
+     *
      */
     @Override
     public DataObject readConfigurationData(InstanceIdentifier<? extends DataObject> path);
-    
+
     /**
-     * Reads data subtree from operational store. 
-     * (Store which is populated by providers, which is usually used to 
+     * Reads data subtree from operational store.
+     * (Store which is populated by providers, which is usually used to
      * capture state of providers. E.g. Topology)
-     * 
+     *
      */
     @Override
     public DataObject readOperationalData(InstanceIdentifier<? extends DataObject> path);
-    
+
     /**
-     * Register a data change listener for particular subtree. 
-     * 
+     * Register a data change listener for particular subtree.
+     *
      * Callback is invoked each time data in subtree changes.
-     * 
+     *
      */
     @Override
     public ListenerRegistration<DataChangeListener> registerDataChangeListener(
index 16d5a24cb5b7c80364edd8dd5dbe4f8b59e6aa97..48ccbfbc955ff9163487fca3523a184cf9d1c688 100644 (file)
@@ -9,19 +9,15 @@ package org.opendaylight.controller.sal.binding.impl;
 \r
 import java.util.Map;
 import java.util.Map.Entry;
-import java.util.concurrent.Future;
 import java.util.concurrent.atomic.AtomicLong;
 
 import org.opendaylight.controller.md.sal.common.impl.service.AbstractDataBroker;
 import org.opendaylight.controller.sal.binding.api.data.DataChangeListener;
 import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
 import org.opendaylight.controller.sal.binding.impl.util.BindingAwareDataReaderRouter;
-import org.opendaylight.controller.sal.common.DataStoreIdentifier;
 import org.opendaylight.yangtools.yang.binding.DataObject;
-import org.opendaylight.yangtools.yang.binding.DataRoot;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.binding.util.DataObjectReadingUtil;
-import org.opendaylight.yangtools.yang.common.RpcResult;
 
 import com.google.common.base.Predicate;
 import com.google.common.collect.ImmutableMap;
@@ -79,68 +75,7 @@ public class DataBrokerImpl extends AbstractDataBroker<InstanceIdentifier<? exte
     }\r
 \r
     @Override\r
-    @Deprecated\r
-    public <T extends DataRoot> T getData(DataStoreIdentifier store, Class<T> rootType) {\r
-        throw new UnsupportedOperationException("Deprecated");\r
-    }\r
-\r
-    @Override\r
-    @Deprecated\r
-    public <T extends DataRoot> T getData(DataStoreIdentifier store, T filter) {\r
-        throw new UnsupportedOperationException("Deprecated");\r
-    }\r
-\r
-    @Override\r
-    @Deprecated\r
-    public <T extends DataRoot> T getCandidateData(DataStoreIdentifier store, Class<T> rootType) {\r
-        throw new UnsupportedOperationException("Deprecated");\r
-    }\r
-\r
-    @Override\r
-    @Deprecated\r
-    public <T extends DataRoot> T getCandidateData(DataStoreIdentifier store, T filter) {\r
-        throw new UnsupportedOperationException("Deprecated");\r
-    }\r
-\r
-    @Override\r
-    @Deprecated\r
-    public RpcResult<DataRoot> editCandidateData(DataStoreIdentifier store, DataRoot changeSet) {\r
-        throw new UnsupportedOperationException("Deprecated");\r
-    }\r
-\r
-    @Override\r
-    @Deprecated\r
-    public Future<RpcResult<Void>> commit(DataStoreIdentifier store) {\r
-        throw new UnsupportedOperationException("Deprecated");\r
-    }\r
-\r
-    @Override\r
-    @Deprecated\r
-    public DataObject getData(InstanceIdentifier<? extends DataObject> data) {\r
-        throw new UnsupportedOperationException("Deprecated");\r
-    }\r
-\r
-    @Override\r
-    @Deprecated\r
-    public DataObject getConfigurationData(InstanceIdentifier<?> data) {\r
-        throw new UnsupportedOperationException("Deprecated");\r
-    }\r
-\r
-    @Override\r
-    @Deprecated\r
-    public void registerChangeListener(InstanceIdentifier<? extends DataObject> path, DataChangeListener changeListener) {\r
-        throw new UnsupportedOperationException("Deprecated");\r
-    }\r
-\r
-    @Override\r
-    @Deprecated\r
-    public void unregisterChangeListener(InstanceIdentifier<? extends DataObject> path,\r
-            DataChangeListener changeListener) {\r
-        throw new UnsupportedOperationException("Deprecated");\r
-    }\r
-\r
-    @Override\r
-    public void close() throws Exception {\r
+    public void close() {\r
 \r
     }
 
diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/DeprecatedDataAPISupport.xtend b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/DeprecatedDataAPISupport.xtend
deleted file mode 100644 (file)
index ee2ade5..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.sal.binding.impl
-
-import org.opendaylight.controller.sal.binding.api.data.DataProviderService
-import org.opendaylight.controller.sal.common.DataStoreIdentifier
-import org.opendaylight.yangtools.yang.binding.DataRoot
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier
-import org.opendaylight.yangtools.yang.binding.DataObject
-import org.opendaylight.controller.sal.binding.api.data.DataChangeListener
-
-abstract class DeprecatedDataAPISupport implements DataProviderService {
-
-    @Deprecated
-    override commit(DataStoreIdentifier store) {
-        throw new UnsupportedOperationException("Deprecated")
-    }
-
-    @Deprecated
-    override editCandidateData(DataStoreIdentifier store, DataRoot changeSet) {
-        throw new UnsupportedOperationException("Deprecated")
-    }
-
-    @Deprecated
-    override <T extends DataRoot> getCandidateData(DataStoreIdentifier store, Class<T> rootType) {
-        throw new UnsupportedOperationException("Deprecated")
-    }
-
-    @Deprecated
-    override <T extends DataRoot> T getCandidateData(DataStoreIdentifier store, T filter) {
-        throw new UnsupportedOperationException("Deprecated")
-    }
-
-    @Deprecated
-    override getConfigurationData(InstanceIdentifier<?> data) {
-        throw new UnsupportedOperationException("Deprecated")
-    }
-
-    @Deprecated
-    override <T extends DataRoot> getData(DataStoreIdentifier store, Class<T> rootType) {
-        throw new UnsupportedOperationException("Deprecated")
-    }
-
-    @Deprecated
-    override <T extends DataRoot> T getData(DataStoreIdentifier store, T filter) {
-        throw new UnsupportedOperationException("Deprecated")
-    }
-
-    @Deprecated
-    override getData(InstanceIdentifier<? extends DataObject> path) {
-        return readOperationalData(path);
-    }
-
-    override registerChangeListener(InstanceIdentifier<? extends DataObject> path, DataChangeListener changeListener) {
-    }
-
-    override unregisterChangeListener(InstanceIdentifier<? extends DataObject> path,
-        DataChangeListener changeListener) {
-    }
-
-}
index 77b411002b01e480bca055c7507ef59c0915d834..64c1ad3ab4035e173858dfacbae6536567aece93 100644 (file)
@@ -7,23 +7,18 @@
  */
 package org.opendaylight.controller.md.sal.binding.util;
 
-import java.util.concurrent.Future;
-
 import org.opendaylight.controller.sal.binding.api.NotificationListener;
 import org.opendaylight.controller.sal.binding.api.NotificationService;
 import org.opendaylight.controller.sal.binding.api.RpcConsumerRegistry;
 import org.opendaylight.controller.sal.binding.api.data.DataBrokerService;
 import org.opendaylight.controller.sal.binding.api.data.DataChangeListener;
 import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
-import org.opendaylight.controller.sal.common.DataStoreIdentifier;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
 import org.opendaylight.yangtools.concepts.Registration;
 import org.opendaylight.yangtools.yang.binding.DataObject;
-import org.opendaylight.yangtools.yang.binding.DataRoot;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.binding.Notification;
 import org.opendaylight.yangtools.yang.binding.RpcService;
-import org.opendaylight.yangtools.yang.common.RpcResult;
 
 import com.google.common.base.Preconditions;
 
@@ -114,72 +109,11 @@ public abstract class AbstractBindingSalConsumerInstance<D extends DataBrokerSer
         return getNotificationBrokerChecked().registerNotificationListener(listener);
     }
 
-    @Override
-    @Deprecated
-    public <T extends DataRoot> T getData(DataStoreIdentifier store, Class<T> rootType) {
-        return getDataBrokerChecked().getData(store, rootType);
-    }
-
-    @Override
-    @Deprecated
-    public <T extends DataRoot> T getData(DataStoreIdentifier store, T filter) {
-        return getDataBrokerChecked().getData(store, filter);
-    }
-
-    @Override
-    @Deprecated
-    public <T extends DataRoot> T getCandidateData(DataStoreIdentifier store, Class<T> rootType) {
-        return getDataBrokerChecked().getCandidateData(store, rootType);
-    }
-
-    @Override
-    @Deprecated
-    public <T extends DataRoot> T getCandidateData(DataStoreIdentifier store, T filter) {
-        return getDataBrokerChecked().getCandidateData(store, filter);
-    }
-
-    @Override
-    @Deprecated
-    public RpcResult<DataRoot> editCandidateData(DataStoreIdentifier store, DataRoot changeSet) {
-        return getDataBrokerChecked().editCandidateData(store, changeSet);
-    }
-
-    @Override
-    @Deprecated
-    public Future<RpcResult<Void>> commit(DataStoreIdentifier store) {
-        return getDataBrokerChecked().commit(store);
-    }
-
-    @Override
-    @Deprecated
-    public DataObject getData(InstanceIdentifier<? extends DataObject> data) {
-        return getDataBrokerChecked().getData(data);
-    }
-
-    @Override
-    @Deprecated
-    public DataObject getConfigurationData(InstanceIdentifier<?> data) {
-        return getDataBrokerChecked().getConfigurationData(data);
-    }
-
     @Override
     public DataModificationTransaction beginTransaction() {
         return getDataBrokerChecked().beginTransaction();
     }
 
-    @Override
-    @Deprecated
-    public void registerChangeListener(InstanceIdentifier<? extends DataObject> path, DataChangeListener changeListener) {
-        getDataBrokerChecked().registerChangeListener(path, changeListener);
-    }
-
-    @Override
-    @Deprecated
-    public void unregisterChangeListener(InstanceIdentifier<? extends DataObject> path,
-            DataChangeListener changeListener) {
-        getDataBrokerChecked().unregisterChangeListener(path, changeListener);
-    }
-
     @Override
     @Deprecated
     public DataObject readConfigurationData(InstanceIdentifier<? extends DataObject> path) {
index 939ff9513513ff1de802746facfdd09844952b76..30f4fc03cb18b13e0d518c7b237f10e471a190f6 100644 (file)
@@ -24,8 +24,8 @@ import org.opendaylight.yangtools.yang.common.RpcResult;
  * this is responsibility of the coordinator (broker or some component of the
  * broker).
  *
- * The commit handlers are responsible for changing the internal state of the
- * provider to reflect the commited changes in data.
+ * Commit handlers are responsible for changing the internal state of the
+ * provider to reflect the committed changes in data.
  *
  * <h3>Two-phase commit</h3>
  *
index 33de1d83dae3cf40ff875625b979a3182783cf20..e201f8835b84182a9f22e9c712a2f8cc0073836f 100644 (file)
@@ -59,7 +59,7 @@ public class TwoPhaseCommit<P extends Path<P>, D extends Object, DCL extends Dat
                 .addAll(transaction.getCreatedOperationalData().keySet())
                 .addAll(transaction.getRemovedOperationalData()).build();
 
-        log.trace("Transaction: {} Affected Subtrees:", transactionId, changedPaths);
+        log.trace("Transaction: {} Affected Subtrees: {}", transactionId, changedPaths);
 
         // The transaction has no effects, let's just shortcut it
         if (changedPaths.isEmpty()) {
@@ -124,7 +124,7 @@ public class TwoPhaseCommit<P extends Path<P>, D extends Object, DCL extends Dat
 
         captureFinalState(listeners);
 
-        log.trace("Transaction: {} Notifying listeners.");
+        log.trace("Transaction: {} Notifying listeners.", transactionId);
 
         publishDataChangeEvent(listeners);
         return Rpcs.<TransactionStatus> getRpcResult(true, TransactionStatus.COMMITED,
index 0299505cdeee6bcef00315507012cbd030f384c1..6b1030a81500f5a909d6df30f69e52208025c482 100644 (file)
@@ -16,11 +16,11 @@ import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
 
 /**
- * {@link Provider}'s implementation of rpc.
- * 
- * In order to expose the rpc to other components, the provider MUST register
- * concrete implementation of this interface
- * 
+ * {@link Provider}'s implementation of an RPC.
+ *
+ * In order to expose an RPC to other components, the provider MUST register
+ * a concrete implementation of this interface.
+ *
  * The registration could be done by :
  * <ul>
  * <li>returning an instance of implementation in the return value of
@@ -29,9 +29,9 @@ import org.opendaylight.yangtools.yang.data.api.CompositeNode;
  * arguments to the
  * {@link ProviderSession#addRpcImplementation(QName, RpcImplementation)}
  * </ul>
- * 
+ *
  * The simplified process of the invocation of rpc is following:
- * 
+ *
  * <ol>
  * <li> {@link Consumer} invokes
  * {@link ConsumerSession#rpc(QName, CompositeNode)}
@@ -42,31 +42,31 @@ import org.opendaylight.yangtools.yang.data.api.CompositeNode;
  * {@link RpcResult}
  * <li> {@link Broker} returns the {@link RpcResult} to {@link Consumer}
  * </ol>
- * 
- * 
+ *
+ *
  */
 public interface RpcImplementation extends Provider.ProviderFunctionality {
 
     /**
      * A set of rpc types supported by implementation.
-     * 
+     *
      * The set of rpc {@link QName}s which are supported by this implementation.
      * This set is used, when {@link Provider} is registered to the SAL, to
      * register and expose the implementation of the returned rpcs.
-     * 
+     *
      * @return Set of QNames identifying supported RPCs
      */
     Set<QName> getSupportedRpcs();
 
     /**
      * Invokes a implementation of specified rpc.
-     * 
-     * 
+     *
+     *
      * @param rpc
      *            Rpc to be invoked
      * @param input
      *            Input data for rpc.
-     * 
+     *
      * @throws IllegalArgumentException
      *             <ul>
      *             <li>If rpc is null.
index abf822087e8f64056d11d05a7b01e9b5cb2bfc91..f380c273732c5fb174c51a07cc2f554b21f394c0 100644 (file)
@@ -44,9 +44,6 @@ import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 import org.opendaylight.yangtools.yang.model.api.SchemaContextListener;
-import org.opendaylight.yangtools.yang.model.api.SchemaServiceListener;
-import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
-import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -57,7 +54,6 @@ import com.google.common.collect.ImmutableSet;
 
 public class SchemaAwareDataStoreAdapter extends AbstractLockableDelegator<DataStore> implements //
         DataStore, //
-        SchemaServiceListener, //
         SchemaContextListener, //
         AutoCloseable {
 
index 6fe56c87edc65ac2399faf8b07c6f0a590d92b2b..416f1941c1f10375fcb27eaf95e83dc65393f5ae 100644 (file)
@@ -8,19 +8,16 @@
 package org.opendaylight.controller.sal.restconf.binding.impl;
 
 import java.net.URL;
-import java.util.concurrent.Future;
+
 import org.opendaylight.controller.sal.binding.api.data.DataBrokerService;
 import org.opendaylight.controller.sal.binding.api.data.DataChangeListener;
 import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
-import org.opendaylight.controller.sal.common.DataStoreIdentifier;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
 import org.opendaylight.yangtools.restconf.client.api.RestconfClientContext;
 import org.opendaylight.yangtools.restconf.client.api.RestconfClientContextFactory;
 import org.opendaylight.yangtools.restconf.client.api.UnsupportedProtocolException;
 import org.opendaylight.yangtools.yang.binding.DataObject;
-import org.opendaylight.yangtools.yang.binding.DataRoot;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMappingService;
 import org.opendaylight.yangtools.yang.model.api.SchemaContextHolder;
 import org.slf4j.Logger;
@@ -35,45 +32,6 @@ public class DataBrokerServiceImpl implements DataBrokerService {
     public DataBrokerServiceImpl(URL baseUrl, BindingIndependentMappingService mappingService, SchemaContextHolder schemaContextHolder) throws UnsupportedProtocolException {
         this.restconfClientContext = restconfClientContextFactory.getRestconfClientContext(baseUrl, mappingService, schemaContextHolder);
     }
-    @Override
-    public <T extends DataRoot> T getData(DataStoreIdentifier store, Class<T> rootType) {
-        return null;
-    }
-
-    @Override
-    public <T extends DataRoot> T getData(DataStoreIdentifier store, T filter) {
-        return null;
-    }
-
-    @Override
-    public <T extends DataRoot> T getCandidateData(DataStoreIdentifier store, Class<T> rootType) {
-        return null;
-    }
-
-    @Override
-    public <T extends DataRoot> T getCandidateData(DataStoreIdentifier store, T filter) {
-        return null;
-    }
-
-    @Override
-    public RpcResult<DataRoot> editCandidateData(DataStoreIdentifier store, DataRoot changeSet) {
-        return null;
-    }
-
-    @Override
-    public Future<RpcResult<Void>> commit(DataStoreIdentifier store) {
-        return null;
-    }
-
-    @Override
-    public DataObject getData(InstanceIdentifier<? extends DataObject> data) {
-        return null;
-    }
-
-    @Override
-    public DataObject getConfigurationData(InstanceIdentifier<?> data) {
-        return null;
-    }
 
     @Override
     public DataModificationTransaction beginTransaction() {
@@ -81,16 +39,6 @@ public class DataBrokerServiceImpl implements DataBrokerService {
         return null;
     }
 
-    @Override
-    public void registerChangeListener(InstanceIdentifier<? extends DataObject> path, DataChangeListener changeListener) {
-
-    }
-
-    @Override
-    public void unregisterChangeListener(InstanceIdentifier<? extends DataObject> path, DataChangeListener changeListener) {
-
-    }
-
     @Override
     public DataObject readConfigurationData(InstanceIdentifier<? extends DataObject> path) {
         //TODO implementation using restconf-client
@@ -109,9 +57,4 @@ public class DataBrokerServiceImpl implements DataBrokerService {
         //TODO implementation using restconf-client
         return null;
     }
-
-
-
-
-
 }
index e31d576d01763a04d5e88e153f1a28997447843d..003ad9853a32a20d7df06262a6c2490e7f6dfe0d 100644 (file)
@@ -14,7 +14,6 @@ import java.util.concurrent.Future;
 import org.opendaylight.controller.sal.binding.api.data.DataBrokerService;
 import org.opendaylight.controller.sal.binding.api.data.DataChangeListener;
 import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
-import org.opendaylight.controller.sal.common.DataStoreIdentifier;
 import org.opendaylight.controller.sal.restconf.broker.listeners.RemoteDataChangeNotificationListener;
 import org.opendaylight.controller.sal.restconf.broker.tools.RemoteStreamTools;
 import org.opendaylight.controller.sal.restconf.broker.transactions.RemoteDataModificationTransaction;
@@ -28,7 +27,6 @@ import org.opendaylight.yangtools.restconf.client.api.RestconfClientContext;
 import org.opendaylight.yangtools.restconf.client.api.event.EventStreamInfo;
 import org.opendaylight.yangtools.restconf.client.api.event.ListenableEventStreamContext;
 import org.opendaylight.yangtools.yang.binding.DataObject;
-import org.opendaylight.yangtools.yang.binding.DataRoot;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.slf4j.Logger;
@@ -46,45 +44,6 @@ public class DataBrokerServiceImpl implements DataBrokerService  {
         this.restconfClientContext = restconfClientContext;
         this.salRemoteService =  this.restconfClientContext.getRpcServiceContext(SalRemoteService.class).getRpcService();
     }
-    @Override
-    public <T extends DataRoot> T getData(DataStoreIdentifier store, Class<T> rootType) {
-        throw new UnsupportedOperationException("Deprecated");
-    }
-
-    @Override
-    public <T extends DataRoot> T getData(DataStoreIdentifier store, T filter) {
-        throw new UnsupportedOperationException("Deprecated");
-    }
-
-    @Override
-    public <T extends DataRoot> T getCandidateData(DataStoreIdentifier store, Class<T> rootType) {
-        throw new UnsupportedOperationException("Deprecated");
-    }
-
-    @Override
-    public <T extends DataRoot> T getCandidateData(DataStoreIdentifier store, T filter) {
-        throw new UnsupportedOperationException("Deprecated");
-    }
-
-    @Override
-    public RpcResult<DataRoot> editCandidateData(DataStoreIdentifier store, DataRoot changeSet) {
-        throw new UnsupportedOperationException("Deprecated");
-    }
-
-    @Override
-    public Future<RpcResult<Void>> commit(DataStoreIdentifier store) {
-        throw new UnsupportedOperationException("Deprecated");
-    }
-
-    @Override
-    public DataObject getData(InstanceIdentifier<? extends DataObject> data) {
-        throw new UnsupportedOperationException("Deprecated");
-    }
-
-    @Override
-    public DataObject getConfigurationData(InstanceIdentifier<?> data) {
-        throw new UnsupportedOperationException("Deprecated");
-    }
 
     @Override
     public DataModificationTransaction beginTransaction() {
@@ -94,16 +53,6 @@ public class DataBrokerServiceImpl implements DataBrokerService  {
         return remoteDataModificationTransaction;
     }
 
-    @Override
-    public void registerChangeListener(InstanceIdentifier<? extends DataObject> path, DataChangeListener changeListener) {
-        throw new UnsupportedOperationException("Deprecated");
-    }
-
-    @Override
-    public void unregisterChangeListener(InstanceIdentifier<? extends DataObject> path, DataChangeListener changeListener) {
-        throw new UnsupportedOperationException("Deprecated");
-    }
-
     @Override
     public DataObject readConfigurationData(InstanceIdentifier<? extends DataObject> path) {
         try {
index 6391a1edad5755cbc97e315b4815356482e54067..b3327f54fd23ece86371f29ada3c97ae036c4a92 100644 (file)
@@ -57,7 +57,8 @@ public class Commit extends AbstractConfigNetconfOperation {
         try {
             status = this.transactionProvider.commitTransaction();
         } catch (final IllegalStateException e) {
-            // FIXME: when can IllegalStateException occur?
+            // TODO Illegal state thrown when no transaction yet for user
+            // Throw other exception type, or create transaction automatically
             logger.warn("Commit failed: ", e);
             final Map<String, String> errorInfo = new HashMap<>();
             errorInfo.put(ErrorTag.operation_failed.name(),
index 83029c44e665ec77bc5796535353277fe481ea43..5642cc7188788fd74a7aeccf7ca8ffa97abd009e 100644 (file)
@@ -25,7 +25,8 @@ public class Activator implements BundleActivator, YangStoreServiceTracker.YangS
     private static final Logger logger = LoggerFactory.getLogger(Activator.class);
 
     private BundleContext context;
-    ServiceRegistration osgiRegistration;
+    private ServiceRegistration osgiRegistration;
+    private ConfigRegistryLookupThread configRegistryLookup = null;
 
     @Override
     public void start(BundleContext context) throws Exception {
@@ -36,20 +37,42 @@ public class Activator implements BundleActivator, YangStoreServiceTracker.YangS
 
     @Override
     public void stop(BundleContext context) throws Exception {
+        if (configRegistryLookup != null) {
+            configRegistryLookup.interrupt();
+        }
     }
 
     @Override
     public synchronized void onYangStoreAdded(YangStoreService yangStoreService) {
-        checkState(osgiRegistration == null, "More than one onYangStoreAdded received");
-        NetconfOperationServiceFactoryImpl factory = new NetconfOperationServiceFactoryImpl(yangStoreService);
-        logger.debug("Registering into OSGi");
-        osgiRegistration = context.registerService(new String[]{NetconfOperationServiceFactory.class.getName()}, factory,
-                new Hashtable<String, Object>());
+        checkState(configRegistryLookup  == null, "More than one onYangStoreAdded received");
+        configRegistryLookup = new ConfigRegistryLookupThread(yangStoreService);
+        configRegistryLookup.start();
     }
 
     @Override
     public synchronized void onYangStoreRemoved() {
-        osgiRegistration.unregister();
+        configRegistryLookup.interrupt();
+        if (osgiRegistration != null) {
+            osgiRegistration.unregister();
+        }
         osgiRegistration = null;
+        configRegistryLookup = null;
+    }
+
+    private class ConfigRegistryLookupThread extends Thread {
+        private final YangStoreService yangStoreService;
+
+        private ConfigRegistryLookupThread(YangStoreService yangStoreService) {
+            super("config-registry-lookup");
+            this.yangStoreService = yangStoreService;
+        }
+
+        @Override
+        public void run() {
+            NetconfOperationServiceFactoryImpl factory = new NetconfOperationServiceFactoryImpl(yangStoreService);
+            logger.debug("Registering into OSGi");
+            osgiRegistration = context.registerService(new String[]{NetconfOperationServiceFactory.class.getName()}, factory,
+                    new Hashtable<String, Object>());
+        }
     }
 }
index 461f22ac2ccc4bf7918062bd09094b2a0e00bc1e..daaf60c1d3662caaa7a5febdb8da90f43eca4e46 100644 (file)
         </dependency>
 
         <!-- test dependencies -->
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>netconf-impl</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>netconf-util</artifactId>
+            <scope>test</scope>
+            <type>test-jar</type>
+        </dependency>
         <dependency>
             <groupId>org.opendaylight.yangtools</groupId>
             <artifactId>mockito-configuration</artifactId>
index 99d122c3c4aaf23dffa71d88a253179686fa99dc..ea2a46dba535f825d0baa7b5dfa58d4b6371c297 100644 (file)
@@ -9,7 +9,6 @@
 package org.opendaylight.controller.netconf.persist.impl;
 
 import com.google.common.base.Preconditions;
-import io.netty.channel.EventLoopGroup;
 import org.opendaylight.controller.config.api.ConflictingVersionException;
 import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
 import org.opendaylight.controller.netconf.api.NetconfMessage;
@@ -29,7 +28,6 @@ import org.xml.sax.SAXException;
 import javax.annotation.concurrent.Immutable;
 import java.io.IOException;
 import java.io.InputStream;
-import java.net.InetSocketAddress;
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.LinkedHashMap;
@@ -41,30 +39,12 @@ import java.util.concurrent.TimeoutException;
 
 @Immutable
 public class ConfigPusher {
-    private static final Logger logger = LoggerFactory.getLogger(ConfigPersisterNotificationHandler.class);
-    private static final int NETCONF_SEND_ATTEMPT_MS_DELAY = 1000;
-    private static final int NETCONF_SEND_ATTEMPTS = 20;
-
-    private final InetSocketAddress address;
-    private final EventLoopGroup nettyThreadGroup;
-
-    // Default timeout for netconf becoming stable
-    public static final long DEFAULT_MAX_WAIT_FOR_CAPABILITIES_MILLIS = TimeUnit.MINUTES.toMillis(2);
-    public static final long DEFAULT_CONNECTION_TIMEOUT_MILLIS = 5000;
-    private final int delayMillis = 5000;
-    private final long maxWaitForCapabilitiesMillis;
-    private final long connectionTimeoutMillis;
-
-    public ConfigPusher(InetSocketAddress address, EventLoopGroup nettyThreadGroup) {
-        this(address, nettyThreadGroup, DEFAULT_MAX_WAIT_FOR_CAPABILITIES_MILLIS, DEFAULT_CONNECTION_TIMEOUT_MILLIS);
-    }
+    private static final Logger logger = LoggerFactory.getLogger(ConfigPusher.class);
+
+    private final ConfigPusherConfiguration configuration;
 
-    public ConfigPusher(InetSocketAddress address, EventLoopGroup nettyThreadGroup,
-                        long maxWaitForCapabilitiesMillis, long connectionTimeoutMillis) {
-        this.address = address;
-        this.nettyThreadGroup = nettyThreadGroup;
-        this.maxWaitForCapabilitiesMillis = maxWaitForCapabilitiesMillis;
-        this.connectionTimeoutMillis = connectionTimeoutMillis;
+    public ConfigPusher(ConfigPusherConfiguration configuration) {
+        this.configuration = configuration;
     }
 
     public synchronized LinkedHashMap<ConfigSnapshotHolder, EditAndCommitResponseWithRetries> pushConfigs(
@@ -95,7 +75,7 @@ public class ConfigPusher {
             throws InterruptedException {
 
         ConflictingVersionException lastException = null;
-        int maxAttempts = 30;
+        int maxAttempts = configuration.netconfPushConfigAttempts;
 
         for (int retryAttempt = 1; retryAttempt <= maxAttempts; retryAttempt++) {
             NetconfClient netconfClient = makeNetconfConnection(configSnapshotHolder.getCapabilities());
@@ -106,7 +86,7 @@ public class ConfigPusher {
             } catch (ConflictingVersionException e) {
                 logger.debug("Conflicting version detected, will retry after timeout");
                 lastException = e;
-                Thread.sleep(1000);
+                Thread.sleep(configuration.netconfPushConfigDelayMs);
             } catch (RuntimeException e) {
                 throw new IllegalStateException("Unable to load " + configSnapshotHolder, e);
             } finally {
@@ -128,24 +108,25 @@ public class ConfigPusher {
         // could be utilized by integration tests
 
         final long pollingStartNanos = System.nanoTime();
-        final long deadlineNanos = pollingStartNanos + TimeUnit.MILLISECONDS.toNanos(maxWaitForCapabilitiesMillis);
+        final long deadlineNanos = pollingStartNanos + TimeUnit.MILLISECONDS.toNanos(configuration.netconfCapabilitiesWaitTimeoutMs);
         int attempt = 0;
 
-        NetconfHelloMessageAdditionalHeader additionalHeader = new NetconfHelloMessageAdditionalHeader("unknown", address.getAddress().getHostAddress(),
-                Integer.toString(address.getPort()), "tcp", "persister");
+        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(nettyThreadGroup,
-                    nettyThreadGroup, additionalHeader, connectionTimeoutMillis);
+            NetconfClientDispatcher netconfClientDispatcher = new NetconfClientDispatcher(configuration.eventLoopGroup,
+                    configuration.eventLoopGroup, additionalHeader, configuration.connectionAttemptTimeoutMs);
             NetconfClient netconfClient;
             try {
-                netconfClient = new NetconfClient(this.toString(), address, delayMillis, netconfClientDispatcher);
+                netconfClient = new NetconfClient(this.toString(), configuration.netconfAddress, configuration.connectionAttemptDelayMs, netconfClientDispatcher);
             } catch (IllegalStateException e) {
-                logger.debug("Netconf {} was not initialized or is not stable, attempt {}", address, attempt, e);
+                logger.debug("Netconf {} was not initialized or is not stable, attempt {}", configuration.netconfAddress, attempt, e);
                 netconfClientDispatcher.close();
-                Thread.sleep(delayMillis);
+                Thread.sleep(configuration.connectionAttemptDelayMs);
                 continue;
             }
             latestCapabilities = netconfClient.getCapabilities();
@@ -159,10 +140,10 @@ public class ConfigPusher {
                     "Expected but not found: {}, all expected {}, current {}",
                     attempt, allNotFound, expectedCaps, latestCapabilities);
             Util.closeClientAndDispatcher(netconfClient);
-            Thread.sleep(delayMillis);
+            Thread.sleep(configuration.connectionAttemptDelayMs);
         }
         if (latestCapabilities == null) {
-            logger.error("Could not connect to the server in {} ms", maxWaitForCapabilitiesMillis);
+            logger.error("Could not connect to the server in {} ms", configuration.netconfCapabilitiesWaitTimeoutMs);
             throw new RuntimeException("Could not connect to netconf server");
         }
         Set<String> allNotFound = computeNotFoundCapabilities(expectedCaps, latestCapabilities);
@@ -229,13 +210,14 @@ public class ConfigPusher {
     }
 
 
-    private static NetconfMessage sendRequestGetResponseCheckIsOK(NetconfMessage request, NetconfClient netconfClient)
+    private NetconfMessage sendRequestGetResponseCheckIsOK(NetconfMessage request, NetconfClient netconfClient)
             throws ConflictingVersionException, IOException {
         try {
-            NetconfMessage netconfMessage = netconfClient.sendMessage(request, NETCONF_SEND_ATTEMPTS, NETCONF_SEND_ATTEMPT_MS_DELAY);
+            NetconfMessage netconfMessage = netconfClient.sendMessage(request,
+                    configuration.netconfSendMessageMaxAttempts, configuration.netconfSendMessageDelayMs);
             NetconfUtil.checkIsMessageOk(netconfMessage);
             return netconfMessage;
-        }catch(ConflictingVersionException e) {
+        } catch(ConflictingVersionException e) {
             logger.trace("conflicting version detected: {}", e.toString());
             throw e;
         } catch (RuntimeException | ExecutionException | InterruptedException | TimeoutException e) { // TODO: change NetconfClient#sendMessage to throw checked exceptions
@@ -330,4 +312,5 @@ public class ConfigPusher {
                     '}';
         }
     }
+
 }
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
new file mode 100644 (file)
index 0000000..aa189f0
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * 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
new file mode 100644 (file)
index 0000000..c26dc8d
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * 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;
+    }
+}
index f168bb36348103525b6895582d73c5c833b3eaed..c1cad4a8ddaba3750b70c3530d7f8324afde8a95 100644 (file)
@@ -134,7 +134,7 @@ public final class PersisterAggregator implements Persister {
     public static PersisterAggregator createFromProperties(PropertiesProviderBaseImpl propertiesProvider) {
         List<PersisterWithConfiguration> persisterWithConfigurations = new ArrayList<>();
         String prefixes = propertiesProvider.getProperty("active");
-        if (prefixes.isEmpty() == false) {
+        if (prefixes!=null && prefixes.isEmpty() == false) {
             String [] keys = prefixes.split(",");
             for (String index: keys) {
                 persisterWithConfigurations.add(PersisterAggregator.loadConfiguration(index, propertiesProvider));
index 1157ddbd83a814be6d7ea4091ea116bf8398255d..1246c78fbe21539589a23d641e58f4a1846da5c8 100644 (file)
@@ -8,10 +8,14 @@
 
 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.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;
@@ -22,16 +26,16 @@ 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;
 
 public class ConfigPersisterActivator implements BundleActivator {
 
     private static final Logger logger = LoggerFactory.getLogger(ConfigPersisterActivator.class);
 
-    private final static MBeanServer platformMBeanServer = ManagementFactory.getPlatformMBeanServer();
-    private static final String IGNORED_MISSING_CAPABILITY_REGEX_SUFFIX = "ignoredMissingCapabilityRegex";
+    public static final String IGNORED_MISSING_CAPABILITY_REGEX_SUFFIX = "ignoredMissingCapabilityRegex";
 
-    private static final String MAX_WAIT_FOR_CAPABILITIES_MILLIS = "maxWaitForCapabilitiesMillis";
+    public static final String MAX_WAIT_FOR_CAPABILITIES_MILLIS = "maxWaitForCapabilitiesMillis";
 
     public static final String NETCONF_CONFIG_PERSISTER = "netconf.config.persister";
 
@@ -39,43 +43,43 @@ public class ConfigPersisterActivator implements BundleActivator {
 
     public static final String DEFAULT_IGNORED_REGEX = "^urn:ietf:params:xml:ns:netconf:base:1.0";
 
+    private final MBeanServer platformMBeanServer;
 
+    private final Optional<ConfigPusherConfiguration> initialConfigForPusher;
     private volatile ConfigPersisterNotificationHandler jmxNotificationHandler;
     private Thread initializationThread;
+    private ThreadFactory initializationThreadFactory;
     private EventLoopGroup nettyThreadGroup;
     private PersisterAggregator persisterAggregator;
 
+    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");
 
         PropertiesProviderBaseImpl propertiesProvider = new PropertiesProviderBaseImpl(context);
 
-        String regexProperty = propertiesProvider.getProperty(IGNORED_MISSING_CAPABILITY_REGEX_SUFFIX);
-        String regex;
-        if (regexProperty != null) {
-            regex = regexProperty;
-        } else {
-            regex = DEFAULT_IGNORED_REGEX;
-        }
-
-        String timeoutProperty = propertiesProvider.getProperty(MAX_WAIT_FOR_CAPABILITIES_MILLIS);
-        long maxWaitForCapabilitiesMillis;
-        if (timeoutProperty == null) {
-            maxWaitForCapabilitiesMillis = ConfigPusher.DEFAULT_MAX_WAIT_FOR_CAPABILITIES_MILLIS;
-        } else {
-            maxWaitForCapabilitiesMillis = Integer.valueOf(timeoutProperty);
-        }
-
-        final Pattern ignoredMissingCapabilityRegex = Pattern.compile(regex);
-        nettyThreadGroup = new NioEventLoopGroup();
+        final Pattern ignoredMissingCapabilityRegex = getIgnoredCapabilitiesProperty(propertiesProvider);
 
         persisterAggregator = PersisterAggregator.createFromProperties(propertiesProvider);
-        final InetSocketAddress address = NetconfConfigUtil.extractTCPNetconfAddress(context,
-                "Netconf is not configured, persister is not operational", true);
-        final ConfigPusher configPusher = new ConfigPusher(address, nettyThreadGroup, maxWaitForCapabilitiesMillis,
-                ConfigPusher.DEFAULT_CONNECTION_TIMEOUT_MILLIS);
 
+        final ConfigPusher configPusher = new ConfigPusher(getConfigurationForPusher(context, propertiesProvider));
 
         // offload initialization to another thread in order to stop blocking activator
         Runnable initializationRunnable = new Runnable() {
@@ -94,17 +98,59 @@ public class ConfigPersisterActivator implements BundleActivator {
                 logger.info("Configuration Persister initialization completed.");
             }
         };
-        initializationThread = new Thread(initializationRunnable, "ConfigPersister-registrator");
+
+        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);
+    }
+
+    private Optional<Long> getMaxWaitForCapabilitiesProperty(PropertiesProviderBaseImpl propertiesProvider) {
+        String timeoutProperty = propertiesProvider.getProperty(MAX_WAIT_FOR_CAPABILITIES_MILLIS);
+        return Optional.fromNullable(timeoutProperty == null ? null : Long.valueOf(timeoutProperty));
+    }
+
+    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();
+
+        if(maxWaitForCapabilitiesMillis.isPresent())
+            configPusherConfigurationBuilder.withNetconfCapabilitiesWaitTimeoutMs(maxWaitForCapabilitiesMillis.get());
+
+        return configPusherConfigurationBuilder
+                .withEventLoopGroup(nettyThreadGroup)
+                .withNetconfAddress(address)
+                .build();
+    }
+
     @Override
     public void stop(BundleContext context) throws Exception {
         initializationThread.interrupt();
         if (jmxNotificationHandler != null) {
             jmxNotificationHandler.close();
         }
-        nettyThreadGroup.shutdownGracefully();
+        if(nettyThreadGroup!=null)
+            nettyThreadGroup.shutdownGracefully();
         persisterAggregator.close();
     }
 }
diff --git a/opendaylight/netconf/config-persister-impl/src/test/java/org/opendaylight/controller/netconf/persist/impl/osgi/ConfigPersisterTest.java b/opendaylight/netconf/config-persister-impl/src/test/java/org/opendaylight/controller/netconf/persist/impl/osgi/ConfigPersisterTest.java
new file mode 100644 (file)
index 0000000..230c747
--- /dev/null
@@ -0,0 +1,273 @@
+/*
+ * 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 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 org.junit.After;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+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 com.google.common.collect.Lists;
+import io.netty.channel.nio.NioEventLoopGroup;
+
+public class ConfigPersisterTest {
+
+    private MockedBundleContext ctx;
+    private ConfigPersisterActivator configPersisterActivator;
+    private static final MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
+
+    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);
+        configPersisterActivator.start(ctx.getBundleContext());
+    }
+
+    @BeforeClass
+    public static void setUp() throws Exception {
+        eventLoopGroup = new NioEventLoopGroup();
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        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);
+
+        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));
+        }
+    }
+
+    private ConfigPusherConfiguration getConfigurationWithOnePushAttempt() {
+        return getConfiguration(500, 1000)
+                    .withNetconfCapabilitiesWaitTimeoutMs(1000)
+                    .withNetconfPushConfigAttempts(1)
+                    .withNetconfPushConfigDelayMs(100)
+                    .withNetconfSendMessageMaxAttempts(3)
+                    .withNetconfSendMessageDelayMs(500).build();
+    }
+
+    @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)) {
+
+            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));
+        }
+    }
+
+    private ConfigPusherConfiguration getConfigurationForSuccess() {
+        return getConfiguration(500, 1000)
+                    .withNetconfCapabilitiesWaitTimeoutMs(1000)
+                    .withNetconfPushConfigAttempts(3)
+                    .withNetconfPushConfigDelayMs(100)
+                    .withNetconfSendMessageMaxAttempts(3)
+                    .withNetconfSendMessageDelayMs(500).build();
+    }
+
+    @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));
+        }
+    }
+
+    @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));
+        }
+    }
+
+    @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)));
+    }
+
+    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
new file mode 100644 (file)
index 0000000..913db28
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+ * 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;
+        }
+    }
+}
diff --git a/opendaylight/netconf/config-persister-impl/src/test/java/org/opendaylight/controller/netconf/persist/impl/osgi/MockedBundleContext.java b/opendaylight/netconf/config-persister-impl/src/test/java/org/opendaylight/controller/netconf/persist/impl/osgi/MockedBundleContext.java
new file mode 100644 (file)
index 0000000..97cf7ec
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * 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 com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+import org.mockito.Mock;
+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.persist.impl.DummyAdapter;
+import org.osgi.framework.BundleContext;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+import static org.mockito.Mockito.doReturn;
+
+final class MockedBundleContext {
+
+    @Mock
+    private BundleContext context;
+
+    MockedBundleContext(String netconfAddress, String netconfPort) {
+        MockitoAnnotations.initMocks(this);
+        initContext(netconfAddress, netconfPort);
+    }
+
+    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);
+
+        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/");
+
+    }
+
+    private void initProp(BundleContext context, String key, String value) {
+        initPropNoPrefix(context, ConfigPersisterActivator.NETCONF_CONFIG_PERSISTER + "." + key, value);
+    }
+
+    private void initPropNoPrefix(BundleContext context, String key, String value) {
+        doReturn(value).when(context).getProperty(key);
+    }
+
+    public static class DummyAdapterWithInitialSnapshot extends DummyAdapter {
+
+        public static final String CONFIG_SNAPSHOT = "config-snapshot";
+        public static String expectedCapability = "cap2";
+
+        @Override
+        public List<ConfigSnapshotHolder> loadLastConfigs() throws IOException {
+            return Lists.newArrayList(getConfigSnapshopt());
+        }
+
+        @Override
+        public Persister instantiate(PropertiesProvider propertiesProvider) {
+            return this;
+        }
+
+        public ConfigSnapshotHolder getConfigSnapshopt() {
+            return new ConfigSnapshotHolder() {
+                @Override
+                public String getConfigSnapshot() {
+                    return "<data><" + CONFIG_SNAPSHOT + "/></data>";
+                }
+
+                @Override
+                public SortedSet<String> getCapabilities() {
+                    TreeSet<String> strings = Sets.newTreeSet();
+                    strings.add(expectedCapability);
+                    return strings;
+                }
+
+                @Override
+                public String toString() {
+                    return getConfigSnapshot();
+                }
+            };
+        }
+    }
+}
diff --git a/opendaylight/netconf/config-persister-impl/src/test/java/org/opendaylight/controller/netconf/persist/impl/osgi/TestingExceptionHandler.java b/opendaylight/netconf/config-persister-impl/src/test/java/org/opendaylight/controller/netconf/persist/impl/osgi/TestingExceptionHandler.java
new file mode 100644 (file)
index 0000000..d42c15b
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * 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 org.junit.matchers.JUnitMatchers;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.fail;
+
+final class TestingExceptionHandler implements Thread.UncaughtExceptionHandler {
+
+    private Throwable t;
+
+    @Override
+    public void uncaughtException(Thread t, Throwable e) {
+        this.t = e;
+    }
+
+    public void assertException(String failMessageSuffix, Class<? extends Exception> exType, String exMessageToContain) {
+        if(t == null) {
+            fail("Should fail to " + failMessageSuffix);
+        }
+        else {
+            assertException(t, exType, exMessageToContain);
+        }
+    }
+
+    public void assertNoException() {
+        assertNull("No exception expected but was " + t, t);
+    }
+
+    private void assertException(Throwable t, Class<? extends Exception> exType, String exMessageToContain) {
+        assertEquals("Expected exception of type " + exType + " but was " + t, exType, t.getClass());
+        if(exMessageToContain!=null) {
+            assertThat(t.getMessage(), JUnitMatchers.containsString(exMessageToContain));
+        }
+    }
+
+    public void assertException(String failMessageSuffix, Class<? extends Exception> exType,
+            String exMessageToContain, Class<? extends Exception> nestedExType, String nestedExMessageToContain,
+            int nestedExDepth) {
+        assertException(failMessageSuffix, exType, exMessageToContain);
+        assertNotNull("Expected nested exception in " + t, t.getCause());
+        assertException(getNestedException(t, nestedExDepth), nestedExType, nestedExMessageToContain);
+    }
+
+    private Throwable getNestedException(Throwable t, int nestedExDepth) {
+
+        int depth = 0;
+        while(t.getCause() != null) {
+            t = t.getCause();
+            depth++;
+            if(nestedExDepth == depth)
+                return t;
+        }
+        throw new IllegalArgumentException("Unable to get nested exception from " + t + " from depth " + nestedExDepth);
+    }
+}
index 28cb4d8194b6c6b67d8afe17790974a5584de4f2..457dda3080fa48adb18e170ba1e36d01d10513f6 100644 (file)
@@ -45,7 +45,7 @@ public class XmlFileLoader {
     public static Document xmlFileToDocument(final String fileName) throws IOException, SAXException,
             ParserConfigurationException {
         try (InputStream resourceAsStream = XmlFileLoader.class.getClassLoader().getResourceAsStream(fileName)) {
-            Preconditions.checkNotNull(resourceAsStream);
+            Preconditions.checkNotNull(resourceAsStream, fileName);
             final Document doc = XmlUtil.readXmlToDocument(resourceAsStream);
             return doc;
         }
index 680b028f9adf6f4de276188745cbeb6ceb4092b9..f93191220b407b43080595edfff2f771d7160aa4 100644 (file)
@@ -37,12 +37,15 @@ import org.opendaylight.controller.networkconfig.neutron.NeutronPort;
 import org.opendaylight.controller.networkconfig.neutron.NeutronSubnet;
 import org.opendaylight.controller.networkconfig.neutron.Neutron_IPs;
 import org.opendaylight.controller.northbound.commons.RestMessages;
+import org.opendaylight.controller.northbound.commons.exception.BadRequestException;
+import org.opendaylight.controller.northbound.commons.exception.ResourceConflictException;
+import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException;
 import org.opendaylight.controller.northbound.commons.exception.ServiceUnavailableException;
 import org.opendaylight.controller.sal.utils.ServiceHelper;
 
 /**
- * Open DOVE Northbound REST APIs.<br>
- * This class provides REST APIs for managing the open DOVE
+ * Neutron Northbound REST APIs.<br>
+ * This class provides REST APIs for managing Neutron Floating IPs
  *
  * <br>
  * <br>
@@ -139,7 +142,7 @@ public class NeutronFloatingIPsNorthbound {
                     + RestMessages.SERVICEUNAVAILABLE.toString());
         }
         if (!floatingIPInterface.floatingIPExists(floatingipUUID))
-            return Response.status(404).build();
+            throw new ResourceNotFoundException("Floating IP UUID doesn't exist.");
         if (fields.size() > 0) {
             NeutronFloatingIP ans = floatingIPInterface.getFloatingIP(floatingipUUID);
             return Response.status(200).entity(
@@ -187,42 +190,42 @@ public class NeutronFloatingIPsNorthbound {
             NeutronFloatingIP singleton = input.getSingleton();
             // check existence of id in cache and return badrequest if exists
             if (floatingIPInterface.floatingIPExists(singleton.getID()))
-                return Response.status(400).build();
+                throw new BadRequestException("Floating IP UUID already exists.");
             // check if the external network is specified, exists, and is an external network
             String externalNetworkUUID = singleton.getFloatingNetworkUUID();
             if (externalNetworkUUID == null)
-                return Response.status(400).build();
+                throw new BadRequestException("external network UUID doesn't exist.");
             if (!networkInterface.networkExists(externalNetworkUUID))
-                return Response.status(400).build();
+                throw new BadRequestException("external network UUID doesn't exist.");
             NeutronNetwork externNetwork = networkInterface.getNetwork(externalNetworkUUID);
             if (!externNetwork.isRouterExternal())
-                return Response.status(400).build();
+                throw new BadRequestException("external network isn't marked router:external");
             // if floating IP is specified, make sure it can come from the network
             String floatingIP = singleton.getFloatingIPAddress();
             if (floatingIP != null) {
                 if (externNetwork.getSubnets().size() > 1)
-                    return Response.status(400).build();
+                    throw new BadRequestException("external network doesn't have a subnet");
                 NeutronSubnet externSubnet = subnetInterface.getSubnet(externNetwork.getSubnets().get(0));
                 if (!externSubnet.isValidIP(floatingIP))
-                    return Response.status(400).build();
+                    throw new BadRequestException("external IP isn't valid for the specified subnet.");
                 if (externSubnet.isIPInUse(floatingIP))
-                    return Response.status(409).build();
+                    throw new ResourceConflictException("floating IP is in use.");
             }
             // if port_id is specified, then check that the port exists and has at least one IP
             String port_id = singleton.getPortUUID();
             if (port_id != null) {
                 String fixedIP = null;        // used for the fixedIP calculation
                 if (!portInterface.portExists(port_id))
-                    return Response.status(404).build();
+                    throw new ResourceNotFoundException("Port UUID doesn't exist.");
                 NeutronPort port = portInterface.getPort(port_id);
                 if (port.getFixedIPs().size() < 1)
-                    return Response.status(400).build();
+                    throw new BadRequestException("port UUID doesn't have an IP address.");
                 // if there is more than one fixed IP then check for fixed_ip_address
                 // and that it is in the list of port addresses
                 if (port.getFixedIPs().size() > 1) {
                     fixedIP = singleton.getFixedIPAddress();
                     if (fixedIP == null)
-                        return Response.status(400).build();
+                        throw new BadRequestException("fixed IP address doesn't exist.");
                     Iterator<Neutron_IPs> i = port.getFixedIPs().iterator();
                     boolean validFixedIP = false;
                     while (i.hasNext() && !validFixedIP) {
@@ -231,15 +234,15 @@ public class NeutronFloatingIPsNorthbound {
                             validFixedIP = true;
                     }
                     if (!validFixedIP)
-                        return Response.status(400).build();
+                        throw new BadRequestException("can't find a valid fixed IP address");
                 } else {
                     fixedIP = port.getFixedIPs().get(0).getIpAddress();
                     if (singleton.getFixedIPAddress() != null && !fixedIP.equalsIgnoreCase(singleton.getFixedIPAddress()))
-                        return Response.status(400).build();
+                        throw new BadRequestException("mismatched fixed IP address in request");
                 }
                 //lastly check that this fixed IP address isn't already used
                 if (port.isBoundToFloatingIP(fixedIP))
-                    return Response.status(409).build();
+                    throw new ResourceConflictException("fixed IP is in use.");
                 singleton.setFixedIPAddress(fixedIP);
             }
             Object[] instances = ServiceHelper.getGlobalInstances(INeutronFloatingIPAware.class, this, null);
@@ -259,7 +262,7 @@ public class NeutronFloatingIPsNorthbound {
                 }
             }
         } else {
-            return Response.status(400).build();
+            throw new BadRequestException("only singleton requests allowed.");
         }
         return Response.status(201).entity(input).build();
     }
@@ -303,14 +306,14 @@ public class NeutronFloatingIPsNorthbound {
                     + RestMessages.SERVICEUNAVAILABLE.toString());
         }
         if (!floatingIPInterface.floatingIPExists(floatingipUUID))
-            return Response.status(404).build();
+            throw new ResourceNotFoundException("Floating IP UUID doesn't exist.");
 
         NeutronFloatingIP sourceFloatingIP = floatingIPInterface.getFloatingIP(floatingipUUID);
         if (!input.isSingleton())
-            return Response.status(400).build();
+            throw new BadRequestException("only singleton requests allowed.");
         NeutronFloatingIP singleton = input.getSingleton();
         if (singleton.getID() != null)
-            return Response.status(400).build();
+            throw new BadRequestException("singleton UUID doesn't exist.");
 
         NeutronNetwork externNetwork = networkInterface.getNetwork(
                 sourceFloatingIP.getFloatingNetworkUUID());
@@ -319,12 +322,12 @@ public class NeutronFloatingIPsNorthbound {
         String floatingIP = singleton.getFloatingIPAddress();
         if (floatingIP != null) {
             if (externNetwork.getSubnets().size() > 1)
-                return Response.status(400).build();
+                throw new BadRequestException("external network doesn't have a subnet.");
             NeutronSubnet externSubnet = subnetInterface.getSubnet(externNetwork.getSubnets().get(0));
             if (!externSubnet.isValidIP(floatingIP))
-                return Response.status(400).build();
+                throw new BadRequestException("floating IP not valid for external subnet");
             if (externSubnet.isIPInUse(floatingIP))
-                return Response.status(409).build();
+                throw new ResourceConflictException("floating IP is in use.");
         }
 
         // if port_id is specified, then check that the port exists and has at least one IP
@@ -332,16 +335,16 @@ public class NeutronFloatingIPsNorthbound {
         if (port_id != null) {
             String fixedIP = null;        // used for the fixedIP calculation
             if (!portInterface.portExists(port_id))
-                return Response.status(404).build();
+                throw new ResourceNotFoundException("Port UUID doesn't exist.");
             NeutronPort port = portInterface.getPort(port_id);
             if (port.getFixedIPs().size() < 1)
-                return Response.status(400).build();
+                throw new BadRequestException("port ID doesn't have a fixed IP address.");
             // if there is more than one fixed IP then check for fixed_ip_address
             // and that it is in the list of port addresses
             if (port.getFixedIPs().size() > 1) {
                 fixedIP = singleton.getFixedIPAddress();
                 if (fixedIP == null)
-                    return Response.status(400).build();
+                    throw new BadRequestException("request doesn't have a fixed IP address");
                 Iterator<Neutron_IPs> i = port.getFixedIPs().iterator();
                 boolean validFixedIP = false;
                 while (i.hasNext() && !validFixedIP) {
@@ -350,16 +353,16 @@ public class NeutronFloatingIPsNorthbound {
                         validFixedIP = true;
                 }
                 if (!validFixedIP)
-                    return Response.status(400).build();
+                    throw new BadRequestException("couldn't find a valid fixed IP address");
             } else {
                 fixedIP = port.getFixedIPs().get(0).getIpAddress();
                 if (singleton.getFixedIPAddress() != null &&
                         !fixedIP.equalsIgnoreCase(singleton.getFixedIPAddress()))
-                    return Response.status(400).build();
+                    throw new BadRequestException("mismatch in fixed IP addresses");
             }
             //lastly check that this fixed IP address isn't already used
             if (port.isBoundToFloatingIP(fixedIP))
-                return Response.status(409).build();
+                throw new ResourceConflictException("fixed IP is in use.");
             singleton.setFixedIPAddress(fixedIP);
         }
         NeutronFloatingIP target = floatingIPInterface.getFloatingIP(floatingipUUID);
@@ -403,7 +406,7 @@ public class NeutronFloatingIPsNorthbound {
                     + RestMessages.SERVICEUNAVAILABLE.toString());
         }
         if (!floatingIPInterface.floatingIPExists(floatingipUUID))
-            return Response.status(404).build();
+            throw new ResourceNotFoundException("Floating IP UUID doesn't exist.");
         // TODO: need to undo port association if it exists
         NeutronFloatingIP singleton = floatingIPInterface.getFloatingIP(floatingipUUID);
         Object[] instances = ServiceHelper.getGlobalInstances(INeutronFloatingIPAware.class, this, null);
index c08ee80e24c44f3551d949e0ff607c7264be9167..d7437c831d4eb38a248c72bbe4050114a358e32e 100644 (file)
@@ -33,12 +33,15 @@ import org.opendaylight.controller.networkconfig.neutron.INeutronNetworkCRUD;
 import org.opendaylight.controller.networkconfig.neutron.NeutronCRUDInterfaces;
 import org.opendaylight.controller.networkconfig.neutron.NeutronNetwork;
 import org.opendaylight.controller.northbound.commons.RestMessages;
+import org.opendaylight.controller.northbound.commons.exception.BadRequestException;
+import org.opendaylight.controller.northbound.commons.exception.ResourceConflictException;
+import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException;
 import org.opendaylight.controller.northbound.commons.exception.ServiceUnavailableException;
 import org.opendaylight.controller.sal.utils.ServiceHelper;
 
 /**
- * Open DOVE Northbound REST APIs for Network.<br>
- * This class provides REST APIs for managing open DOVE internals related to Networks
+ * Neutron Northbound REST APIs for Network.<br>
+ * This class provides REST APIs for managing neutron Networks
  *
  * <br>
  * <br>
@@ -154,7 +157,7 @@ public class NeutronNetworksNorthbound {
                     + RestMessages.SERVICEUNAVAILABLE.toString());
         }
         if (!networkInterface.networkExists(netUUID)) {
-            return Response.status(404).build();
+            throw new ResourceNotFoundException("network UUID does not exist.");
         }
         if (fields.size() > 0) {
             NeutronNetwork ans = networkInterface.getNetwork(netUUID);
@@ -189,7 +192,7 @@ public class NeutronNetworksNorthbound {
              * network ID can't already exist
              */
             if (networkInterface.networkExists(singleton.getID())) {
-                return Response.status(400).build();
+                throw new BadRequestException("network UUID already exists");
             }
 
             Object[] instances = ServiceHelper.getGlobalInstances(INeutronNetworkAware.class, this, null);
@@ -226,10 +229,10 @@ public class NeutronNetworksNorthbound {
                  * already in this bulk request
                  */
                 if (networkInterface.networkExists(test.getID())) {
-                    return Response.status(400).build();
+                    throw new BadRequestException("network UUID already exists");
                 }
                 if (testMap.containsKey(test.getID())) {
-                    return Response.status(400).build();
+                    throw new BadRequestException("network UUID already exists");
                 }
                 if (instances != null) {
                     for (Object instance: instances) {
@@ -285,10 +288,10 @@ public class NeutronNetworksNorthbound {
          * network has to exist and only a single delta is supported
          */
         if (!networkInterface.networkExists(netUUID)) {
-            return Response.status(404).build();
+            throw new ResourceNotFoundException("network UUID does not exist.");
         }
         if (!input.isSingleton()) {
-            return Response.status(400).build();
+            throw new BadRequestException("only singleton edits supported");
         }
         NeutronNetwork delta = input.getSingleton();
 
@@ -297,7 +300,7 @@ public class NeutronNetworksNorthbound {
          */
         if (delta.getID() != null || delta.getTenantID() != null ||
                 delta.getStatus() != null) {
-            return Response.status(400).build();
+            throw new BadRequestException("attribute edit blocked by Neutron");
         }
 
         Object[] instances = ServiceHelper.getGlobalInstances(INeutronNetworkAware.class, this, null);
@@ -347,10 +350,10 @@ public class NeutronNetworksNorthbound {
          * network has to exist and not be in use before it can be removed
          */
         if (!networkInterface.networkExists(netUUID)) {
-            return Response.status(404).build();
+            throw new ResourceNotFoundException("network UUID does not exist.");
         }
         if (networkInterface.networkInUse(netUUID)) {
-            return Response.status(409).build();
+            throw new ResourceConflictException("Network ID in use");
         }
 
         NeutronNetwork singleton = networkInterface.getNetwork(netUUID);
index c26e0229d0271ed6a6a0a10f0e17755176f69595..9f24e79ea02ab3fd6fbbd722fe8c86054a3b4470 100644 (file)
@@ -36,12 +36,15 @@ import org.opendaylight.controller.networkconfig.neutron.NeutronPort;
 import org.opendaylight.controller.networkconfig.neutron.NeutronSubnet;
 import org.opendaylight.controller.networkconfig.neutron.Neutron_IPs;
 import org.opendaylight.controller.northbound.commons.RestMessages;
+import org.opendaylight.controller.northbound.commons.exception.BadRequestException;
+import org.opendaylight.controller.northbound.commons.exception.ResourceConflictException;
+import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException;
 import org.opendaylight.controller.northbound.commons.exception.ServiceUnavailableException;
 import org.opendaylight.controller.sal.utils.ServiceHelper;
 
 /**
- * Open DOVE Northbound REST APIs.<br>
- * This class provides REST APIs for managing the open DOVE
+ * Neutron Northbound REST APIs.<br>
+ * This class provides REST APIs for managing neutron port objects
  *
  * <br>
  * <br>
@@ -148,7 +151,7 @@ public class NeutronPortsNorthbound {
                     + RestMessages.SERVICEUNAVAILABLE.toString());
         }
         if (!portInterface.portExists(portUUID)) {
-            return Response.status(404).build();
+            throw new ResourceNotFoundException("port UUID does not exist.");
         }
         if (fields.size() > 0) {
             NeutronPort ans = portInterface.getPort(portUUID);
@@ -200,20 +203,20 @@ public class NeutronPortsNorthbound {
              * have a valid MAC and the MAC not be in use
              */
             if (singleton.getNetworkUUID() == null) {
-                return Response.status(400).build();
+                throw new BadRequestException("network UUID musy be specified");
             }
             if (portInterface.portExists(singleton.getID())) {
-                return Response.status(400).build();
+                throw new BadRequestException("port UUID already exists");
             }
             if (!networkInterface.networkExists(singleton.getNetworkUUID())) {
-                return Response.status(404).build();
+                throw new ResourceNotFoundException("network UUID does not exist.");
             }
             if (singleton.getMacAddress() == null ||
                     !singleton.getMacAddress().matches(mac_regex)) {
-                return Response.status(400).build();
+                throw new BadRequestException("MAC address not properly formatted");
             }
             if (portInterface.macInUse(singleton.getMacAddress())) {
-                return Response.status(409).build();
+                throw new ResourceConflictException("MAC Address is in use.");
             }
             Object[] instances = ServiceHelper.getGlobalInstances(INeutronPortAware.class, this, null);
             if (instances != null) {
@@ -237,21 +240,21 @@ public class NeutronPortsNorthbound {
                 while (fixedIPIterator.hasNext()) {
                     Neutron_IPs ip = fixedIPIterator.next();
                     if (ip.getSubnetUUID() == null) {
-                        return Response.status(400).build();
+                        throw new BadRequestException("subnet UUID not specified");
                     }
                     if (!subnetInterface.subnetExists(ip.getSubnetUUID())) {
-                        return Response.status(400).build();
+                        throw new BadRequestException("subnet UUID must exists");
                     }
                     NeutronSubnet subnet = subnetInterface.getSubnet(ip.getSubnetUUID());
                     if (!singleton.getNetworkUUID().equalsIgnoreCase(subnet.getNetworkUUID())) {
-                        return Response.status(400).build();
+                        throw new BadRequestException("network UUID must match that of subnet");
                     }
                     if (ip.getIpAddress() != null) {
                         if (!subnet.isValidIP(ip.getIpAddress())) {
-                            return Response.status(400).build();
+                            throw new BadRequestException("IP address is not valid");
                         }
                         if (subnet.isIPInUse(ip.getIpAddress())) {
-                            return Response.status(409).build();
+                            throw new ResourceConflictException("IP address is in use.");
                         }
                     }
                 }
@@ -279,32 +282,32 @@ public class NeutronPortsNorthbound {
                  * can't already contain a new port with the same UUID
                  */
                 if (portInterface.portExists(test.getID())) {
-                    return Response.status(400).build();
+                    throw new BadRequestException("port UUID already exists");
                 }
                 if (testMap.containsKey(test.getID())) {
-                    return Response.status(400).build();
+                    throw new BadRequestException("port UUID already exists");
                 }
                 for (NeutronPort check : testMap.values()) {
                     if (test.getMacAddress().equalsIgnoreCase(check.getMacAddress())) {
-                        return Response.status(409).build();
+                        throw new ResourceConflictException("MAC address already allocated");
                     }
                     for (Neutron_IPs test_fixedIP : test.getFixedIPs()) {
                         for (Neutron_IPs check_fixedIP : check.getFixedIPs()) {
                             if (test_fixedIP.getIpAddress().equals(check_fixedIP.getIpAddress())) {
-                                return Response.status(409).build();
+                                throw new ResourceConflictException("IP address already allocated");
                             }
                         }
                     }
                 }
                 testMap.put(test.getID(), test);
                 if (!networkInterface.networkExists(test.getNetworkUUID())) {
-                    return Response.status(404).build();
+                    throw new ResourceNotFoundException("network UUID does not exist.");
                 }
                 if (!test.getMacAddress().matches(mac_regex)) {
-                    return Response.status(400).build();
+                    throw new BadRequestException("MAC address not properly formatted");
                 }
                 if (portInterface.macInUse(test.getMacAddress())) {
-                    return Response.status(409).build();
+                    throw new ResourceConflictException("MAC address in use");
                 }
                 if (instances != null) {
                     for (Object instance : instances) {
@@ -327,23 +330,23 @@ public class NeutronPortsNorthbound {
                     while (fixedIPIterator.hasNext()) {
                         Neutron_IPs ip = fixedIPIterator.next();
                         if (ip.getSubnetUUID() == null) {
-                            return Response.status(400).build();
+                            throw new BadRequestException("subnet UUID must be specified");
                         }
                         if (!subnetInterface.subnetExists(ip.getSubnetUUID())) {
-                            return Response.status(400).build();
+                            throw new BadRequestException("subnet UUID doesn't exists");
                         }
                         NeutronSubnet subnet = subnetInterface.getSubnet(ip.getSubnetUUID());
                         if (!test.getNetworkUUID().equalsIgnoreCase(subnet.getNetworkUUID())) {
-                            return Response.status(400).build();
+                            throw new BadRequestException("network UUID must match that of subnet");
                         }
                         if (ip.getIpAddress() != null) {
                             if (!subnet.isValidIP(ip.getIpAddress())) {
-                                return Response.status(400).build();
+                                throw new BadRequestException("ip address not valid");
                             }
                             //TODO: need to add consideration for a fixed IP being assigned the same address as a allocated IP in the
                             //same bulk create
                             if (subnet.isIPInUse(ip.getIpAddress())) {
-                                return Response.status(409).build();
+                                throw new ResourceConflictException("IP address in use");
                             }
                         }
                     }
@@ -399,11 +402,11 @@ public class NeutronPortsNorthbound {
 
         // port has to exist and only a single delta is supported
         if (!portInterface.portExists(portUUID)) {
-            return Response.status(404).build();
+            throw new ResourceNotFoundException("port UUID does not exist.");
         }
         NeutronPort target = portInterface.getPort(portUUID);
         if (!input.isSingleton()) {
-            return Response.status(400).build();
+            throw new BadRequestException("only singleton edit suported");
         }
         NeutronPort singleton = input.getSingleton();
         NeutronPort original = portInterface.getPort(portUUID);
@@ -411,7 +414,7 @@ public class NeutronPortsNorthbound {
         // deltas restricted by Neutron
         if (singleton.getID() != null || singleton.getTenantID() != null ||
                 singleton.getStatus() != null) {
-            return Response.status(400).build();
+            throw new BadRequestException("attribute change blocked by Neutron");
         }
 
         Object[] instances = ServiceHelper.getGlobalInstances(INeutronPortAware.class, this, null);
@@ -432,21 +435,21 @@ public class NeutronPortsNorthbound {
             while (fixedIPIterator.hasNext()) {
                 Neutron_IPs ip = fixedIPIterator.next();
                 if (ip.getSubnetUUID() == null) {
-                    return Response.status(400).build();
+                    throw new BadRequestException("subnet UUID must be specified");
                 }
                 if (!subnetInterface.subnetExists(ip.getSubnetUUID())) {
-                    return Response.status(400).build();
+                    throw new BadRequestException("subnet UUID doesn't exist.");
                 }
                 NeutronSubnet subnet = subnetInterface.getSubnet(ip.getSubnetUUID());
                 if (!target.getNetworkUUID().equalsIgnoreCase(subnet.getNetworkUUID())) {
-                    return Response.status(400).build();
+                    throw new BadRequestException("network UUID must match that of subnet");
                 }
                 if (ip.getIpAddress() != null) {
                     if (!subnet.isValidIP(ip.getIpAddress())) {
-                        return Response.status(400).build();
+                        throw new BadRequestException("invalid IP address");
                     }
                     if (subnet.isIPInUse(ip.getIpAddress())) {
-                        return Response.status(409).build();
+                        throw new ResourceConflictException("IP address in use");
                     }
                 }
             }
@@ -454,7 +457,7 @@ public class NeutronPortsNorthbound {
 
         //        TODO: Support change of security groups
         // update the port and return the modified object
-                portInterface.updatePort(portUUID, singleton);
+        portInterface.updatePort(portUUID, singleton);
         NeutronPort updatedPort = portInterface.getPort(portUUID);
         if (instances != null) {
             for (Object instance : instances) {
@@ -488,7 +491,7 @@ public class NeutronPortsNorthbound {
 
         // port has to exist and not be owned by anyone.  then it can be removed from the cache
         if (!portInterface.portExists(portUUID)) {
-            return Response.status(404).build();
+            throw new ResourceNotFoundException("port UUID does not exist.");
         }
         NeutronPort port = portInterface.getPort(portUUID);
         if (port.getDeviceID() != null ||
index fc7e0f7efbf429014859c760caf86add6f326518..17b2fcfcf9ef43437903f499dc4da2aceb61983b 100644 (file)
@@ -37,13 +37,16 @@ import org.opendaylight.controller.networkconfig.neutron.NeutronRouter;
 import org.opendaylight.controller.networkconfig.neutron.NeutronRouter_Interface;
 import org.opendaylight.controller.networkconfig.neutron.NeutronSubnet;
 import org.opendaylight.controller.northbound.commons.RestMessages;
+import org.opendaylight.controller.northbound.commons.exception.BadRequestException;
+import org.opendaylight.controller.northbound.commons.exception.ResourceConflictException;
+import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException;
 import org.opendaylight.controller.northbound.commons.exception.ServiceUnavailableException;
 import org.opendaylight.controller.sal.utils.ServiceHelper;
 
 
 /**
- * Open DOVE Northbound REST APIs.<br>
- * This class provides REST APIs for managing the open DOVE
+ * Neutron Northbound REST APIs.<br>
+ * This class provides REST APIs for managing neutron routers
  *
  * <br>
  * <br>
@@ -141,8 +144,9 @@ public class NeutronRoutersNorthbound {
             throw new ServiceUnavailableException("Router CRUD Interface "
                     + RestMessages.SERVICEUNAVAILABLE.toString());
         }
-        if (!routerInterface.routerExists(routerUUID))
-            return Response.status(404).build();
+        if (!routerInterface.routerExists(routerUUID)) {
+            throw new ResourceNotFoundException("Router UUID not found");
+        }
         if (fields.size() > 0) {
             NeutronRouter ans = routerInterface.getRouter(routerUUID);
             return Response.status(200).entity(
@@ -184,14 +188,14 @@ public class NeutronRoutersNorthbound {
              * exists and has been designated as "router:external"
              */
             if (routerInterface.routerExists(singleton.getID()))
-                return Response.status(400).build();
+                throw new BadRequestException("router UUID already exists");
             if (singleton.getExternalGatewayInfo() != null) {
                 String externNetworkPtr = singleton.getExternalGatewayInfo().getNetworkID();
                 if (!networkInterface.networkExists(externNetworkPtr))
-                    return Response.status(400).build();
+                    throw new BadRequestException("External Network Pointer doesn't exist");
                 NeutronNetwork externNetwork = networkInterface.getNetwork(externNetworkPtr);
                 if (!externNetwork.isRouterExternal())
-                    return Response.status(400).build();
+                    throw new BadRequestException("External Network Pointer isn't marked as router:external");
             }
             Object[] instances = ServiceHelper.getGlobalInstances(INeutronRouterAware.class, this, null);
             if (instances != null) {
@@ -218,7 +222,7 @@ public class NeutronRoutersNorthbound {
             /*
              * only singleton router creates supported
              */
-            return Response.status(400).build();
+            throw new BadRequestException("Only singleton router creates supported");
         }
         return Response.status(201).entity(input).build();
     }
@@ -256,9 +260,9 @@ public class NeutronRoutersNorthbound {
          * router has to exist and only a single delta can be supplied
          */
         if (!routerInterface.routerExists(routerUUID))
-            return Response.status(404).build();
+            throw new ResourceNotFoundException("Router UUID not found");
         if (!input.isSingleton())
-            return Response.status(400).build();
+            throw new BadRequestException("Only single router deltas supported");
         NeutronRouter singleton = input.getSingleton();
         NeutronRouter original = routerInterface.getRouter(routerUUID);
 
@@ -267,7 +271,7 @@ public class NeutronRoutersNorthbound {
          */
         if (singleton.getID() != null || singleton.getTenantID() != null ||
                 singleton.getStatus() != null)
-            return Response.status(400).build();
+            throw new BadRequestException("Request attribute change not allowed");
 
         Object[] instances = ServiceHelper.getGlobalInstances(INeutronRouterAware.class, this, null);
         if (instances != null) {
@@ -285,10 +289,10 @@ public class NeutronRoutersNorthbound {
         if (singleton.getExternalGatewayInfo() != null) {
             String externNetworkPtr = singleton.getExternalGatewayInfo().getNetworkID();
             if (!networkInterface.networkExists(externNetworkPtr))
-                return Response.status(400).build();
+                throw new BadRequestException("External Network Pointer does not exist");
             NeutronNetwork externNetwork = networkInterface.getNetwork(externNetworkPtr);
             if (!externNetwork.isRouterExternal())
-                return Response.status(400).build();
+                throw new BadRequestException("External Network Pointer isn't marked as router:external");
         }
 
         /*
@@ -330,9 +334,9 @@ public class NeutronRoutersNorthbound {
          * verify that the router exists and is not in use before removing it
          */
         if (!routerInterface.routerExists(routerUUID))
-            return Response.status(404).build();
+            throw new ResourceNotFoundException("Router UUID not found");
         if (routerInterface.routerInUse(routerUUID))
-            return Response.status(409).build();
+            throw new ResourceConflictException("Router UUID in Use");
         NeutronRouter singleton = routerInterface.getRouter(routerUUID);
         Object[] instances = ServiceHelper.getGlobalInstances(INeutronRouterAware.class, this, null);
         if (instances != null) {
@@ -393,28 +397,27 @@ public class NeutronRoutersNorthbound {
          *  or a port id, but not both, this code assumes that the plugin has filled everything in for us and so both must be present
          */
         if (!routerInterface.routerExists(routerUUID))
-            return Response.status(400).build();
+            throw new BadRequestException("Router UUID doesn't exist");
         NeutronRouter target = routerInterface.getRouter(routerUUID);
         if (input.getSubnetUUID() == null ||
                     input.getPortUUID() == null)
-                return Response.status(400).build();
+            throw new BadRequestException("Must specify at subnet id, port id or both");
 
         // check that the port is part of the subnet
         NeutronSubnet targetSubnet = subnetInterface.getSubnet(input.getSubnetUUID());
         if (targetSubnet == null)
-            return Response.status(400).build();
+            throw new BadRequestException("Subnet id doesn't exist");
         NeutronPort targetPort = portInterface.getPort(input.getPortUUID());
         if (targetPort == null)
-            return Response.status(400).build();
+            throw new BadRequestException("Port id doesn't exist");
         if (!targetSubnet.getPortsInSubnet().contains(targetPort))
-            return Response.status(400).build();
+            throw new BadRequestException("Port id not part of subnet id");
 
         if (targetPort.getFixedIPs().size() != 1)
-            return Response.status(400).build();
+            throw new BadRequestException("Port id must have a single fixedIP address");
         if (targetPort.getDeviceID() != null ||
                 targetPort.getDeviceOwner() != null)
-            return Response.status(409).build();
-
+            throw new ResourceConflictException("Target Port already allocated");
         Object[] instances = ServiceHelper.getGlobalInstances(INeutronRouterAware.class, this, null);
         if (instances != null) {
             for (Object instance : instances) {
@@ -475,7 +478,7 @@ public class NeutronRoutersNorthbound {
 
         // verify the router exists
         if (!routerInterface.routerExists(routerUUID))
-            return Response.status(400).build();
+            throw new BadRequestException("Router does not exist");
         NeutronRouter target = routerInterface.getRouter(routerUUID);
 
         /*
@@ -486,7 +489,7 @@ public class NeutronRoutersNorthbound {
                 input.getSubnetUUID() != null) {
             NeutronPort port = portInterface.getGatewayPort(input.getSubnetUUID());
             if (port == null)
-                return Response.status(404).build();
+                throw new ResourceNotFoundException("Port UUID not found");
             input.setPortUUID(port.getID());
             input.setID(target.getID());
             input.setTenantID(target.getTenantID());
@@ -543,9 +546,18 @@ public class NeutronRoutersNorthbound {
         if (input.getPortUUID() != null &&
                 input.getSubnetUUID() != null) {
             NeutronPort port = portInterface.getPort(input.getPortUUID());
+            if (port == null) {
+                throw new ResourceNotFoundException("Port UUID not found");
+            }
+            if (port.getFixedIPs() == null) {
+                throw new ResourceNotFoundException("Port UUID jas no fixed IPs");
+            }
             NeutronSubnet subnet = subnetInterface.getSubnet(input.getSubnetUUID());
+            if (subnet == null) {
+                throw new ResourceNotFoundException("Subnet UUID not found");
+            }
             if (!subnet.isValidIP(port.getFixedIPs().get(0).getIpAddress()))
-                return Response.status(409).build();
+                throw new ResourceConflictException("Target Port IP not in Target Subnet");
             input.setID(target.getID());
             input.setTenantID(target.getTenantID());
             Object[] instances = ServiceHelper.getGlobalInstances(INeutronRouterAware.class, this, null);
@@ -566,6 +578,6 @@ public class NeutronRoutersNorthbound {
         }
 
         // have to specify either a port ID or a subnet ID
-        return Response.status(400).build();
+        throw new BadRequestException("Must specify port id or subnet id or both");
     }
 }
index dffac55c5030ac96da1b52bde366f009cbb4a63d..224fcb5f01ceaaaa662d2c9bbe0655892da463a2 100644 (file)
@@ -33,13 +33,16 @@ import org.opendaylight.controller.networkconfig.neutron.INeutronSubnetCRUD;
 import org.opendaylight.controller.networkconfig.neutron.NeutronCRUDInterfaces;
 import org.opendaylight.controller.networkconfig.neutron.NeutronSubnet;
 import org.opendaylight.controller.northbound.commons.RestMessages;
+import org.opendaylight.controller.northbound.commons.exception.BadRequestException;
+import org.opendaylight.controller.northbound.commons.exception.ResourceConflictException;
+import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException;
 import org.opendaylight.controller.northbound.commons.exception.InternalServerErrorException;
 import org.opendaylight.controller.northbound.commons.exception.ServiceUnavailableException;
 import org.opendaylight.controller.sal.utils.ServiceHelper;
 
 /**
- * Open DOVE Northbound REST APIs.<br>
- * This class provides REST APIs for managing open DOVE internals related to Subnets
+ * Neutron Northbound REST APIs for Subnets.<br>
+ * This class provides REST APIs for managing neutron Subnets
  *
  * <br>
  * <br>
@@ -142,7 +145,7 @@ public class NeutronSubnetsNorthbound {
                     + RestMessages.SERVICEUNAVAILABLE.toString());
         }
         if (!subnetInterface.subnetExists(subnetUUID)) {
-            return Response.status(404).build();
+            throw new ResourceNotFoundException("subnet UUID does not exist.");
         }
         if (fields.size() > 0) {
             NeutronSubnet ans = subnetInterface.getSubnet(subnetUUID);
@@ -190,19 +193,19 @@ public class NeutronSubnetsNorthbound {
              *  *then* add the subnet to the cache
              */
             if (subnetInterface.subnetExists(singleton.getID())) {
-                return Response.status(400).build();
+                throw new BadRequestException("subnet UUID already exists");
             }
             if (!networkInterface.networkExists(singleton.getNetworkUUID())) {
-                return Response.status(404).build();
+                throw new ResourceNotFoundException("network UUID does not exist.");
             }
             if (!singleton.isValidCIDR()) {
-                return Response.status(400).build();
+                throw new BadRequestException("invaild CIDR");
             }
             if (!singleton.initDefaults()) {
                 throw new InternalServerErrorException("subnet object could not be initialized properly");
             }
             if (singleton.gatewayIP_Pool_overlap()) {
-                return Response.status(409).build();
+                throw new ResourceConflictException("IP pool overlaps with gateway");
             }
             Object[] instances = ServiceHelper.getGlobalInstances(INeutronSubnetAware.class, this, null);
             if (instances != null) {
@@ -240,20 +243,20 @@ public class NeutronSubnetsNorthbound {
                     throw new InternalServerErrorException("subnet object could not be initialized properly");
                 }
                 if (subnetInterface.subnetExists(test.getID())) {
-                    return Response.status(400).build();
+                    throw new BadRequestException("subnet UUID already exists");
                 }
                 if (testMap.containsKey(test.getID())) {
-                    return Response.status(400).build();
+                    throw new BadRequestException("subnet UUID already exists");
                 }
                 testMap.put(test.getID(), test);
                 if (!networkInterface.networkExists(test.getNetworkUUID())) {
-                    return Response.status(404).build();
+                    throw new ResourceNotFoundException("network UUID does not exist.");
                 }
                 if (!test.isValidCIDR()) {
-                    return Response.status(400).build();
+                    throw new BadRequestException("Invalid CIDR");
                 }
                 if (test.gatewayIP_Pool_overlap()) {
-                    return Response.status(409).build();
+                    throw new ResourceConflictException("IP pool overlaps with gateway");
                 }
                 if (instances != null) {
                     for (Object instance : instances) {
@@ -312,10 +315,10 @@ public class NeutronSubnetsNorthbound {
          * verify the subnet exists and there is only one delta provided
          */
         if (!subnetInterface.subnetExists(subnetUUID)) {
-            return Response.status(404).build();
+            throw new ResourceNotFoundException("subnet UUID does not exist.");
         }
         if (!input.isSingleton()) {
-            return Response.status(400).build();
+            throw new BadRequestException("Only singleton edit supported");
         }
         NeutronSubnet delta = input.getSingleton();
         NeutronSubnet original = subnetInterface.getSubnet(subnetUUID);
@@ -326,7 +329,7 @@ public class NeutronSubnetsNorthbound {
         if (delta.getID() != null || delta.getTenantID() != null ||
                 delta.getIpVersion() != null || delta.getCidr() != null ||
                 delta.getAllocationPools() != null) {
-            return Response.status(400).build();
+            throw new BadRequestException("Attribute edit blocked by Neutron");
         }
 
         Object[] instances = ServiceHelper.getGlobalInstances(INeutronSubnetAware.class, this, null);
@@ -378,7 +381,7 @@ public class NeutronSubnetsNorthbound {
          * verify the subnet exists and it isn't currently in use
          */
         if (!subnetInterface.subnetExists(subnetUUID)) {
-            return Response.status(404).build();
+            throw new ResourceNotFoundException("subnet UUID does not exist.");
         }
         if (subnetInterface.subnetInUse(subnetUUID)) {
             return Response.status(409).build();
index 16868f55170deab4120ac7064fa849cb6da87c9d..326755309d7f01a01749055753a302d1248acd47 100644 (file)
@@ -15,7 +15,7 @@
   </scm>
 
   <artifactId>sal</artifactId>
-  <version>0.7.1-SNAPSHOT</version>
+  <version>0.8.1-SNAPSHOT</version>
   <packaging>bundle</packaging>
 
   <build>
index 7f398db6f12e8def650afa50be7a0ee888460906..0dffee9c474de57797117a218f4aa019e6a33e85 100644 (file)
@@ -85,6 +85,19 @@ public class Edge implements Serializable {
         }
     }
 
+    /**
+     * Create the reversed edge
+     * @return The reversed edge.
+     */
+    public Edge reverse() {
+        Edge re;
+        try {
+            re = new Edge(this.headNodeConnector, this.tailNodeConnector);
+        } catch (ConstructionException e) {
+            re = null;
+        }
+        return re;
+    }
     /**
      * getter of edge
      *
index 31b3ec6a5a164c96cc1c8ea04aa06e35b8197eab..ba2394131d84cb962696d2e955d4bbeb0866f277 100644 (file)
@@ -17,6 +17,8 @@
 package org.opendaylight.controller.sal.core;
 
 import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.LinkedList;
 import java.util.List;
 
@@ -81,6 +83,39 @@ public class Path implements Serializable {
         this.edges = edges;
     }
 
+    /**
+     * Create the reversed path
+     * @return The reversed path
+     */
+    public Path reverse() {
+        int j = edges.size(); // size always > 0
+        Edge[]  aEdges = new Edge[j];
+        for (Edge e : edges) {
+            j--;
+            aEdges[j] = e.reverse();
+        }
+        Path rp;
+        try {
+         rp = new Path(Arrays.asList(aEdges));
+        } catch (ConstructionException ce) {
+            rp = null;
+        }
+        return rp;
+    }
+
+    /**
+     * Return the list of nodes of this path, the first node is the start node
+     * @return the list of nodes
+     */
+    public List<Node> getNodes() {
+        List<Node> nl = new ArrayList<Node>();
+        nl.add(this.getStartNode());
+        for (Edge e : edges) {
+            nl.add(e.getHeadNodeConnector().getNode());
+        }
+        return nl;
+    }
+
     /**
      * Copy Construct for a path
      *