Merge "Added container wrapper against action to support augmentation"
authorEd Warnicke <eaw@cisco.com>
Tue, 17 Jun 2014 11:22:17 +0000 (11:22 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Tue, 17 Jun 2014 11:22:17 +0000 (11:22 +0000)
75 files changed:
features/base/pom.xml
features/base/src/main/resources/features.xml
features/controller/pom.xml [new file with mode: 0644]
features/controller/src/main/resources/features.xml [new file with mode: 0644]
opendaylight/commons/opendaylight/pom.xml
opendaylight/containermanager/api/src/main/java/org/opendaylight/controller/containermanager/IContainerManagerShell.java [new file with mode: 0644]
opendaylight/containermanager/implementation/src/main/java/org/opendaylight/controller/containermanager/internal/Activator.java
opendaylight/containermanager/implementation/src/main/java/org/opendaylight/controller/containermanager/internal/ContainerManager.java
opendaylight/containermanager/shell/pom.xml [new file with mode: 0644]
opendaylight/containermanager/shell/src/main/java/org/opendaylight/controller/containermanager/shell/AddContainer.java [new file with mode: 0644]
opendaylight/containermanager/shell/src/main/java/org/opendaylight/controller/containermanager/shell/AddContainerEntry.java [new file with mode: 0644]
opendaylight/containermanager/shell/src/main/java/org/opendaylight/controller/containermanager/shell/AddContainerFlow.java [new file with mode: 0644]
opendaylight/containermanager/shell/src/main/java/org/opendaylight/controller/containermanager/shell/ContainermgrGetAuthorizedGroups.java [new file with mode: 0644]
opendaylight/containermanager/shell/src/main/java/org/opendaylight/controller/containermanager/shell/ContainermgrGetAuthorizedResources.java [new file with mode: 0644]
opendaylight/containermanager/shell/src/main/java/org/opendaylight/controller/containermanager/shell/ContainermgrGetResourcesForGroup.java [new file with mode: 0644]
opendaylight/containermanager/shell/src/main/java/org/opendaylight/controller/containermanager/shell/ContainermgrGetRoles.java [new file with mode: 0644]
opendaylight/containermanager/shell/src/main/java/org/opendaylight/controller/containermanager/shell/ContainermgrGetUserLevel.java [new file with mode: 0644]
opendaylight/containermanager/shell/src/main/java/org/opendaylight/controller/containermanager/shell/ContainermgrGetUserResources.java [new file with mode: 0644]
opendaylight/containermanager/shell/src/main/java/org/opendaylight/controller/containermanager/shell/CreateContainer.java [new file with mode: 0644]
opendaylight/containermanager/shell/src/main/java/org/opendaylight/controller/containermanager/shell/Pfc.java [new file with mode: 0644]
opendaylight/containermanager/shell/src/main/java/org/opendaylight/controller/containermanager/shell/Psc.java [new file with mode: 0644]
opendaylight/containermanager/shell/src/main/java/org/opendaylight/controller/containermanager/shell/Psd.java [new file with mode: 0644]
opendaylight/containermanager/shell/src/main/java/org/opendaylight/controller/containermanager/shell/Psm.java [new file with mode: 0644]
opendaylight/containermanager/shell/src/main/java/org/opendaylight/controller/containermanager/shell/Psp.java [new file with mode: 0644]
opendaylight/containermanager/shell/src/main/java/org/opendaylight/controller/containermanager/shell/RemoveContainer.java [new file with mode: 0644]
opendaylight/containermanager/shell/src/main/java/org/opendaylight/controller/containermanager/shell/RemoveContainerEntry.java [new file with mode: 0644]
opendaylight/containermanager/shell/src/main/java/org/opendaylight/controller/containermanager/shell/RemoveContainerFlow.java [new file with mode: 0644]
opendaylight/containermanager/shell/src/main/java/org/opendaylight/controller/containermanager/shell/SaveConfig.java [new file with mode: 0644]
opendaylight/containermanager/shell/src/main/resources/OSGI-INF/blueprint/blueprint.xml [new file with mode: 0644]
opendaylight/containermanager/shell/src/test/java/org/opendaylight/controller/containermanager/shell/ContainerManagerShellTest.java [new file with mode: 0644]
opendaylight/distribution/opendaylight-karaf/pom.xml
opendaylight/distribution/opendaylight-karaf/src/main/resources/etc/custom.properties
opendaylight/distribution/opendaylight-karaf/src/main/resources/etc/startup.properties
opendaylight/distribution/opendaylight-karaf/src/main/resources/etc/system.properties [new file with mode: 0644]
opendaylight/md-sal/pom.xml
opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/OptimisticLockFailedException.java [new file with mode: 0644]
opendaylight/md-sal/sal-distributed-datastore/pom.xml [new file with mode: 0644]
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DistributedDataStore.java [new file with mode: 0644]
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ListenerRegistrationProxy.java [new file with mode: 0644]
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/TransactionChainProxy.java [new file with mode: 0644]
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/TransactionProxy.java [new file with mode: 0644]
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/config/yang/config/distributed_datastore_provider/DistributedDataStoreProviderModule.java [new file with mode: 0644]
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/config/yang/config/distributed_datastore_provider/DistributedDataStoreProviderModuleFactory.java [new file with mode: 0644]
opendaylight/md-sal/sal-distributed-datastore/src/main/yang/distributed-datastore-provider.yang [new file with mode: 0644]
opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/DistributedDataStoreTest.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMDataBroker.java
opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMTransactionChain.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/AbstractDOMForwardedCompositeTransaction.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/AbstractDOMForwardedTransactionFactory.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMDataBrokerImpl.java
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMDataBrokerTransactionChainImpl.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMDataCommitCoordinatorImpl.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMDataCommitErrorInvoker.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMDataCommitErrorListener.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMDataCommitExecutor.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMDataCommitImplementation.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMForwardedReadOnlyTransaction.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMForwardedReadWriteTransaction.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMForwardedWriteTransaction.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/TransactionCommitFailedExceptionMapper.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/InMemoryDOMDataStore.java
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/ConflictingModificationAppliedException.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/DataTree.java
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/DataValidationFailedException.java [moved from opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/DataPreconditionFailedException.java with 85% similarity]
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/IncorrectDataStructureException.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/InMemoryDataTree.java
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/ModificationApplyOperation.java
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/NormalizedNodeContainerModificationStrategy.java
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/SchemaAwareApplyOperation.java
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/ValueNodeModificationStrategy.java
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/osgi/DOMDataBrokerProxy.java
opendaylight/md-sal/sal-dom-broker/src/test/java/org/opendaylight/controller/md/sal/dom/broker/impl/BlockingTransactionChainListener.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-broker/src/test/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMTransactionChainTest.java [new file with mode: 0644]
opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-xml/yang/basic-module.yang
pom.xml

index d12432c6b4f8dd8e7d194d524eb1f88713a7805b..922b2d6bdfbd7652df204f2e70597a11fc0a76ac 100644 (file)
@@ -8,7 +8,7 @@
     <relativePath>../../opendaylight/commons/opendaylight</relativePath>
   </parent>
   <artifactId>base-features</artifactId>
-  <packaging>kar</packaging>
+  <packaging>pom</packaging>
   <name>${project.artifactId}</name>
   <description>Base Features POM</description>
   <properties>
       </resource>
     </resources>
     <plugins>
-      <plugin>
-        <groupId>org.apache.karaf.tooling</groupId>
-        <artifactId>karaf-maven-plugin</artifactId>
-        <version>${karaf.version}</version>
-        <extensions>true</extensions>
-        <executions>
-          <execution>
-            <id>features-create-kar</id>
-            <goals>
-              <goal>features-create-kar</goal>
-            </goals>
-            <configuration>
-              <featuresFile>${project.build.directory}/classes/${features.file}</featuresFile>
-            </configuration>
-          </execution>
-        </executions>
-        <!-- There is no useful configuration for the kar mojo. The features-generate-descriptor mojo configuration may be useful -->
-      </plugin>
       <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-resources-plugin</artifactId>
index 23051f5a9ab88ba7a7f82dc75b9ad2abfbf0355c..5677ab66d0bf971e43541583ce6b5955a57906e0 100644 (file)
       <bundle start="true" start-level="35">mvn:orbit/org.apache.juli.extras/7.0.32.v201211081135</bundle>
       <bundle start="true" start-level="35">mvn:orbit/org.apache.tomcat.api/7.0.32.v201211081135</bundle>
       <bundle start="true" start-level="35">mvn:orbit/org.apache.tomcat.util/7.0.32.v201211201952</bundle>
-      <bundle start="true" start-level="35">wrap:mvn:virgomirror/org.eclipse.jdt.core.compiler.batch/3.8.0.I20120518-2145</bundle>
    </feature>
    <feature name="base-spring" description="Opendaylight Spring Support" version="${spring.version}">
       <bundle>mvn:org.ow2.asm/asm-all/${asm.version}</bundle>
diff --git a/features/controller/pom.xml b/features/controller/pom.xml
new file mode 100644 (file)
index 0000000..ddaf773
--- /dev/null
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project>
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.opendaylight.controller</groupId>
+    <artifactId>commons.opendaylight</artifactId>
+    <version>1.4.2-SNAPSHOT</version>
+    <relativePath>../../opendaylight/commons/opendaylight</relativePath>
+  </parent>
+  <artifactId>controller-features</artifactId>
+  <packaging>pom</packaging>
+  <name>${project.artifactId}</name>
+  <description>Features POM</description>
+  <properties>
+    <features.file>features.xml</features.file>
+  </properties>
+  <build>
+    <resources>
+      <resource>
+        <filtering>true</filtering>
+        <directory>src/main/resources</directory>
+      </resource>
+    </resources>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-resources-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>filter</id>
+            <goals>
+              <goal>resources</goal>
+            </goals>
+            <phase>generate-resources</phase>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
+        <groupId>org.codehaus.mojo</groupId>
+        <artifactId>build-helper-maven-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>attach-artifacts</id>
+            <goals>
+              <goal>attach-artifact</goal>
+            </goals>
+            <phase>package</phase>
+            <configuration>
+              <artifacts>
+                <artifact>
+                  <file>${project.build.directory}/classes/${features.file}</file>
+                  <type>xml</type>
+                  <classifier>features</classifier>
+                </artifact>
+              </artifacts>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/features/controller/src/main/resources/features.xml b/features/controller/src/main/resources/features.xml
new file mode 100644 (file)
index 0000000..1ae210a
--- /dev/null
@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<features name="controller-${project.version}" xmlns="http://karaf.apache.org/xmlns/features/v1.2.0"
+   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+   xsi:schemaLocation="http://karaf.apache.org/xmlns/features/v1.2.0 http://karaf.apache.org/xmlns/features/v1.2.0">
+
+   <feature name="odl-hosttracker" description="Controller Service: Host Tracker">
+      <feature>odl-clustering</feature>
+      <feature>odl-managers</feature>
+      <feature>odl-sal</feature>
+      <bundle>mvn:org.opendaylight.controller/hosttracker/${hosttracker.api.version}</bundle>
+      <bundle>mvn:org.opendaylight.controller/hosttracker.implementation/${hosttracker.implementation.version}</bundle>
+   </feature>
+   <feature name="odl-sal" description="Service Abstraction Layer"
+      version="${sal.version}">
+      <feature>base-felix-dm</feature>
+      <bundle start="true" start-level="35">mvn:org.apache.commons/commons-lang3/${commons.lang.version}</bundle>
+      <bundle>mvn:org.osgi/org.osgi.compendium/${osgi.compendium.version}</bundle>
+      <bundle>mvn:org.apache.felix/org.apache.felix.dependencymanager/${felix.dependencymanager.version}</bundle>
+      <bundle>mvn:org.opendaylight.controller/sal/${sal.version}</bundle>
+      <!-- The SAL Implementation doesn't follow API versioning, should be revisited in the bundle -->
+      <bundle>mvn:org.opendaylight.controller/sal.implementation/${sal.implementation.version}</bundle>
+      <bundle>mvn:org.opendaylight.controller/sal.networkconfiguration/${sal.networkconfiguration.version}</bundle>
+      <bundle>mvn:org.opendaylight.controller/sal.networkconfiguration.implementation/${sal.networkconfiguration.version}</bundle>
+      <bundle>mvn:org.opendaylight.controller/sal.connection/${sal.connection.version}</bundle>
+      <bundle>mvn:org.opendaylight.controller/sal.connection.implementation/${sal.connection.version}</bundle>
+   </feature>
+   <feature name="odl-clustering" description="Controller Service: Clustering">
+      <feature>transaction</feature>
+      <feature>base-felix-dm</feature>
+      <feature>base-eclipselink-persistence</feature>
+      <feature>odl-sal</feature>
+      <bundle>mvn:org.opendaylight.controller/clustering.services/${clustering.services.version}</bundle>
+      <bundle>mvn:org.opendaylight.controller/clustering.services-implementation/${clustering.services_implementation.version}</bundle>
+      <bundle>mvn:org.opendaylight.controller/clustering.stub/${clustering.stub.version}</bundle>
+   </feature>
+   <feature name="odl-legacy-configuration">
+      <feature>odl-sal</feature>
+      <bundle>mvn:org.opendaylight.controller/configuration/${configuration.version}</bundle>
+      <bundle>mvn:org.opendaylight.controller/configuration.implementation/${configuration.implementation.version}</bundle>
+   </feature>
+   <feature name="odl-configuration" description="Controller Service: Configuration">
+      <!-- org.opendaylight.controller.config.yangjmxgenerator is missing -->
+      <bundle>mvn:org.opendaylight.controller/config-api/${config.version}</bundle>
+      <bundle>mvn:org.opendaylight.controller/config-manager/${config.version}</bundle>
+      <bundle>mvn:org.opendaylight.controller/config-netconf-connector/${netconf.version}</bundle>
+      <bundle>mvn:org.opendaylight.controller/config-persister-api/${config.version}</bundle>
+      <bundle>mvn:org.opendaylight.controller/config-persister-directory-xml-adapter/${config.version}</bundle>
+      <bundle>mvn:org.opendaylight.controller/config-persister-file-xml-adapter/${config.version}</bundle>
+      <bundle>mvn:org.opendaylight.controller/config-persister-impl/${netconf.version}</bundle>
+      <bundle>mvn:org.opendaylight.controller/yang-jmx-generator/${yang-jmx-generator.version}</bundle>
+   </feature>
+   <feature name="odl-managers" description="Big boss">
+      <feature>odl-legacy-configuration</feature>
+      <feature>base-spring-security</feature>
+      <feature>base-felix-dm</feature>
+      <feature>odl-clustering</feature>
+      <bundle>mvn:org.opendaylight.controller.thirdparty/net.sf.jung2/2.0.1</bundle>
+      <bundle>mvn:org.opendaylight.controller/appauth/${appauth.version}</bundle>
+      <bundle>mvn:org.opendaylight.controller/hosttracker/${hosttracker.api.version}</bundle>
+      <bundle>mvn:org.opendaylight.controller/hosttracker.implementation/${hosttracker.implementation.version}</bundle>
+      <bundle>mvn:org.opendaylight.controller/switchmanager/${switchmanager.api.version}</bundle>
+      <bundle>mvn:org.opendaylight.controller/switchmanager.implementation/${switchmanager.implementation.version}</bundle>
+      <bundle>mvn:org.opendaylight.controller/statisticsmanager/${statisticsmanager.version}</bundle>
+      <bundle>mvn:org.opendaylight.controller/statisticsmanager.implementation/${statisticsmanager.implementation.version}</bundle>
+      <bundle>mvn:org.opendaylight.controller/forwardingrulesmanager/${forwardingrulesmanager.version}</bundle>
+      <bundle>mvn:org.opendaylight.controller/forwardingrulesmanager.implementation/${forwardingrulesmanager.implementation.version}</bundle>
+      <bundle>mvn:org.opendaylight.controller/usermanager/${usermanager.version}</bundle>
+      <bundle>mvn:org.opendaylight.controller/usermanager.implementation/${usermanager.version}</bundle>
+      <bundle>mvn:org.opendaylight.controller/containermanager/${containermanager.version}</bundle>
+      <bundle>mvn:org.opendaylight.controller/containermanager.implementation/${containermanager.version}</bundle>
+      <bundle>mvn:org.opendaylight.controller/topologymanager/${topologymanager.version}</bundle>
+      <bundle>mvn:org.opendaylight.controller/forwarding.staticrouting</bundle>
+      <bundle>mvn:org.opendaylight.controller/routing.dijkstra_implementation</bundle>
+      <bundle>mvn:org.opendaylight.controller/connectionmanager</bundle>
+      <bundle>mvn:org.opendaylight.controller/connectionmanager.implementation</bundle>
+   </feature>
+</features>
index c3c8168bd77abcf00d84baeabad33576984c54e5..92e4ee0b481a7bd58c1ef0143fa4a97a0095a8e9 100644 (file)
   </prerequisites>
 
   <properties>
+    <akka.version>2.3.2</akka.version>
     <aopalliance.version>1.0.0</aopalliance.version>
     <appauth.version>0.4.2-SNAPSHOT</appauth.version>
+    <archetype-app-northbound>0.0.1-SNAPSHOT</archetype-app-northbound>
     <aries.util.version>1.1.0</aries.util.version>
     <!-- Controller Modules Versions -->
     <arphandler.version>0.5.2-SNAPSHOT</arphandler.version>
+    <arphandler.version>0.5.2-SNAPSHOT</arphandler.version>
     <asm.version>4.1</asm.version>
     <!-- Plugin Versions -->
     <bouncycastle.version>1.50</bouncycastle.version>
     <bundle.plugin.version>2.4.0</bundle.plugin.version>
+    <bundlescanner.api.version>0.4.2-SNAPSHOT</bundlescanner.api.version>
+    <bundlescanner.implementation.version>0.4.2-SNAPSHOT</bundlescanner.implementation.version>
     <bundlescanner.version>0.4.2-SNAPSHOT</bundlescanner.version>
     <checkstyle.version>2.10</checkstyle.version>
     <clustering.services.version>0.5.1-SNAPSHOT</clustering.services.version>
     <clustering.stub.version>0.4.2-SNAPSHOT</clustering.stub.version>
     <clustering.test.version>0.4.2-SNAPSHOT</clustering.test.version>
     <commmons.northbound.version>0.4.2-SNAPSHOT</commmons.northbound.version>
+    <commons.checkstyle.version>0.0.3-SNAPSHOT</commons.checkstyle.version>
     <!-- Third Party Versions -->
     <commons.codec.version>1.7</commons.codec.version>
     <commons.fileupload.version>1.2.2</commons.fileupload.version>
     <commons.httpclient.version>0.1.2-SNAPSHOT</commons.httpclient.version>
     <commons.io.version>2.4</commons.io.version>
     <commons.lang.version>3.1</commons.lang.version>
+    <commons.logback_settings.version>0.0.2-SNAPSHOT</commons.logback_settings.version>
     <commons.net.version>3.0.1</commons.net.version>
+    <commons.opendaylight.commons.httpclient>0.1.2-SNAPSHOT</commons.opendaylight.commons.httpclient>
+    <commons.opendaylight.concepts.version>0.5.2-SNAPSHOT</commons.opendaylight.concepts.version>
+    <commons.opendaylight.version>1.4.2-SNAPSHOT</commons.opendaylight.version>
+    <commons.parent.version>1.0.2-SNAPSHOT</commons.parent.version>
     <compiler.version>2.3.2</compiler.version>
     <concepts.version>0.5.2-SNAPSHOT</concepts.version>
     <config.version>0.2.5-SNAPSHOT</config.version>
     <connectionmanager.version>0.1.2-SNAPSHOT</connectionmanager.version>
     <containermanager.it.version>0.5.2-SNAPSHOT</containermanager.it.version>
     <containermanager.northbound.version>0.4.2-SNAPSHOT</containermanager.northbound.version>
+    <containermanager.shell.version>0.5.2-SNAPSHOT</containermanager.shell.version>
     <containermanager.version>0.5.2-SNAPSHOT</containermanager.version>
     <controllermanager.northbound.version>0.0.2-SNAPSHOT</controllermanager.northbound.version>
     <corsfilter.version>7.0.42</corsfilter.version>
     <ctrie.version>0.2.0</ctrie.version>
     <devices.web.version>0.4.2-SNAPSHOT</devices.web.version>
+    <dummy-console.version>1.1.0-SNAPSHOT</dummy-console.version>
     <eclipse.persistence.version>2.5.0</eclipse.persistence.version>
     <!-- enforcer version -->
     <enforcer.version>1.3.1</enforcer.version>
@@ -79,6 +92,8 @@
     <hosttracker.implementation.version>0.5.2-SNAPSHOT</hosttracker.implementation.version>
     <hosttracker.northbound.version>0.4.2-SNAPSHOT</hosttracker.northbound.version>
     <hosttracker_new.api.version>0.4.2-SNAPSHOT</hosttracker_new.api.version>
+    <hosttracker_new.implementation.version>0.4.2-SNAPSHOT</hosttracker_new.implementation.version>
+    <httpservice-bridge.northbound.version>0.0.2-SNAPSHOT</httpservice-bridge.northbound.version>
     <ietf-inet-types.version>2010.09.24.4-SNAPSHOT</ietf-inet-types.version>
     <ietf-restconf.version>2013.10.19.1-SNAPSHOT</ietf-restconf.version>
     <ietf-topology.version>2013.10.21.2-SNAPSHOT</ietf-topology.version>
     <jersey2.version>2.8</jersey2.version>
     <jettison.version>1.3.3</jettison.version>
     <jmxGeneratorPath>src/main/yang-gen-config</jmxGeneratorPath>
+    <jolokia-bridge.version>0.0.2-SNAPSHOT</jolokia-bridge.version>
     <jolokia.version>1.1.4</jolokia.version>
     <jsr305.api.version>2.0.1</jsr305.api.version>
     <jsr311.api.version>1.1.1</jsr311.api.version>
     <jsr311.v2.api.version>2.0</jsr311.v2.api.version>
     <junit.version>4.8.1</junit.version>
     <karaf.branding.version>1.0.0-SNAPSHOT</karaf.branding.version>
+    <karaf.shell.version>3.0.0</karaf.shell.version>
     <karaf.version>3.0.1</karaf.version>
     <logback.version>1.0.9</logback.version>
     <logging.bridge.version>0.4.2-SNAPSHOT</logging.bridge.version>
     <networkconfig.neutron.version>0.4.2-SNAPSHOT</networkconfig.neutron.version>
     <!-- ODL repository / plugin repository -->
     <nexusproxy>http://nexus.opendaylight.org/content</nexusproxy>
+    <northbound.commons.version>0.4.2-SNAPSHOT</northbound.commons.version>
+    <northbound.hosttracker.version>1.4.2-SNAPSHOT</northbound.hosttracker.version>
+    <northbound.jolokia.version>1.4.2-SNAPSHOT</northbound.jolokia.version>
     <opendaylight-l2-types.version>2013.08.27.4-SNAPSHOT</opendaylight-l2-types.version>
     <org.json.version>20080701</org.json.version>
     <osgi-brandfragment.web.version>0.0.2-SNAPSHOT</osgi-brandfragment.web.version>
     <samples.loadbalancer.northbound.version>0.4.2-SNAPSHOT</samples.loadbalancer.northbound.version>
     <samples.simpleforwarding.version>0.4.2-SNAPSHOT</samples.simpleforwarding.version>
     <sanitytest.version>0.4.2-SNAPSHOT</sanitytest.version>
+    <scala.version>2.11</scala.version>
     <security.version>0.4.2-SNAPSHOT</security.version>
     <sitedeploy>dav:http://nexus.opendaylight.org/content/sites/site</sitedeploy>
     <siteplugin>3.2</siteplugin>
     <xtend.dstdir>src/main/xtend-gen</xtend.dstdir>
     <xtend.version>2.4.3</xtend.version>
     <yang-ext.version>2013.09.07.4-SNAPSHOT</yang-ext.version>
+    <yang-jmx-generator.version>1.0.0-SNAPSHOT</yang-jmx-generator.version>
     <yangtools.version>0.6.2-SNAPSHOT</yangtools.version>
   </properties>
 
         <artifactId>jersey-core</artifactId>
         <version>${jersey.version}</version>
       </dependency>
+
       <dependency>
         <groupId>com.sun.jersey</groupId>
         <artifactId>jersey-server</artifactId>
         <version>${jersey.version}</version>
       </dependency>
+
+      <dependency>
+        <groupId>com.typesafe.akka</groupId>
+        <artifactId>akka-actor_${scala.version}</artifactId>
+        <version>${akka.version}</version>
+      </dependency>
+
+      <dependency>
+        <groupId>com.typesafe.akka</groupId>
+        <artifactId>akka-cluster_${scala.version}</artifactId>
+        <version>${akka.version}</version>
+      </dependency>
+
+      <dependency>
+        <groupId>com.typesafe.akka</groupId>
+        <artifactId>akka-persistence-experimental_${scala.version}</artifactId>
+        <version>${akka.version}</version>
+      </dependency>
+
+      <dependency>
+        <groupId>com.typesafe.akka</groupId>
+        <artifactId>akka-remote_${scala.version}</artifactId>
+        <version>${akka.version}</version>
+      </dependency>
       <dependency>
         <groupId>commons-codec</groupId>
         <artifactId>commons-codec</artifactId>
         <artifactId>containermanager.northbound</artifactId>
         <version>${containermanager.northbound.version}</version>
       </dependency>
+      <dependency>
+        <groupId>org.opendaylight.controller</groupId>
+        <artifactId>containermanager.shell</artifactId>
+        <version>${containermanager.shell.version}</version>
+      </dependency>
       <dependency>
         <groupId>org.opendaylight.controller</groupId>
         <artifactId>controllermanager.northbound</artifactId>
         <artifactId>chameleon-mbeans</artifactId>
         <version>1.0.0</version>
       </dependency>
+      <dependency>
+        <groupId>org.scala-lang</groupId>
+        <artifactId>scala-library</artifactId>
+        <version>${scala.version}.1</version>
+      </dependency>
       <dependency>
         <groupId>org.slf4j</groupId>
         <artifactId>jcl-over-slf4j</artifactId>
           <includeTestSourceDirectory>true</includeTestSourceDirectory>
           <sourceDirectory>${project.basedir}</sourceDirectory>
           <includes>**\/*.java,**\/*.xml,**\/*.ini,**\/*.sh,**\/*.bat</includes>
-          <excludes>**\/target\/,**\/bin\/,**\/target-ide\/,**\/${jmxGeneratorPath}\/,**\/${salGeneratorPath}\/</excludes>
+          <excludes>**\/target\/,**\/bin\/,**\/target-ide\/,**\/${jmxGeneratorPath}\/,**\/${salGeneratorPath}\/,**\/xtend-gen\/</excludes>
         </configuration>
         <dependencies>
           <dependency>
diff --git a/opendaylight/containermanager/api/src/main/java/org/opendaylight/controller/containermanager/IContainerManagerShell.java b/opendaylight/containermanager/api/src/main/java/org/opendaylight/controller/containermanager/IContainerManagerShell.java
new file mode 100644 (file)
index 0000000..2024b18
--- /dev/null
@@ -0,0 +1,25 @@
+package org.opendaylight.controller.containermanager;
+
+import java.util.List;
+
+public interface IContainerManagerShell {
+    public List<String> psc();
+    public List<String> pfc();
+    public List<String> psd();
+    public List<String> psp();
+    public List<String> psm();
+    public List<String> addContainer(String arg1, String arg2);
+    public List<String> createContainer(String arg1, String arg2);
+    public List<String> removeContainerShell(String arg1);
+    public List<String> addContainerEntry(String arg1, String arg2, String arg3);
+    public List<String> removeContainerEntry(String arg1, String arg2, String arg3);
+    public List<String> addContainerFlow(String arg1, String arg2, String arg3);
+    public List<String> removeContainerFlow(String arg1, String arg2);
+    public List<String> containermgrGetRoles();
+    public List<String> containermgrGetAuthorizedGroups(String arg1);
+    public List<String> containermgrGetAuthorizedResources(String arg1);
+    public List<String> containermgrGetResourcesForGroup(String arg1);
+    public List<String> containermgrGetUserLevel(String arg1);
+    public List<String> containermgrGetUserResources(String arg1);
+    public List<String> saveConfig();
+}
\ No newline at end of file
index 616a0f24f33c5f856885981284b98ea1f9c4ec83..61c8ab6c6eb112a48141bb76753b8bec0c1fc78c 100644 (file)
 package org.opendaylight.controller.containermanager.internal;
 
 import org.eclipse.osgi.framework.console.CommandProvider;
+
 import java.util.Dictionary;
 import java.util.HashSet;
 import java.util.Set;
 import java.util.Hashtable;
+
 import org.opendaylight.controller.containermanager.IContainerManager;
+import org.opendaylight.controller.containermanager.IContainerManagerShell;
 import org.apache.felix.dm.Component;
 import org.opendaylight.controller.clustering.services.ICacheUpdateAware;
 import org.opendaylight.controller.clustering.services.IClusterGlobalServices;
@@ -124,7 +127,8 @@ public class Activator extends ComponentActivatorAbstractBase {
                             CommandProvider.class.getName(),
                             IContainerInternal.class.getName(),
                             IContainerAuthorization.class.getName(),
-                            ICacheUpdateAware.class.getName()}, props);
+                            ICacheUpdateAware.class.getName(),
+                            IContainerManagerShell.class.getName()}, props);
 
             c.add(createServiceDependency()
                     .setService(IClusterGlobalServices.class)
index 0fee183b67b8c1be06725b310c4111fbf3f9f8a8..98378e81354742327e912199a44619febbaa5905 100644 (file)
@@ -44,6 +44,7 @@ import org.opendaylight.controller.containermanager.ContainerFlowChangeEvent;
 import org.opendaylight.controller.containermanager.ContainerFlowConfig;
 import org.opendaylight.controller.containermanager.IContainerAuthorization;
 import org.opendaylight.controller.containermanager.IContainerManager;
+import org.opendaylight.controller.containermanager.IContainerManagerShell;
 import org.opendaylight.controller.containermanager.NodeConnectorsChangeEvent;
 import org.opendaylight.controller.sal.authorization.AppRoleLevel;
 import org.opendaylight.controller.sal.authorization.Privilege;
@@ -71,7 +72,7 @@ import org.slf4j.LoggerFactory;
 
 public class ContainerManager extends Authorization<String> implements IContainerManager, IObjectReader,
         CommandProvider, ICacheUpdateAware<String, Object>, IContainerInternal, IContainerAuthorization,
-        IConfigurationAware {
+        IConfigurationAware, IContainerManagerShell {
     private static final Logger logger = LoggerFactory.getLogger(ContainerManager.class);
     private static String CONTAINERS_FILE_NAME = "containers.conf";
     private static final String allContainersGroup = "allContainers";
@@ -1619,4 +1620,286 @@ public class ContainerManager extends Authorization<String> implements IContaine
     public boolean inContainerMode() {
         return this.containerConfigs.size() > 0;
     }
+
+    public List<String> psc() {
+        List<String> result = new ArrayList<String>();
+        for (Map.Entry<String, ContainerConfig> entry : containerConfigs.entrySet()) {
+            ContainerConfig sc = entry.getValue();
+            result.add(String.format("%s: %s", sc.getContainerName(), sc.toString()));
+        }
+        result.add("Total number of containers: " + containerConfigs.entrySet().size());
+        return result;
+    }
+
+    public List<String> pfc() {
+        List<String> result = new ArrayList<String>();
+        for (Map.Entry<String, ContainerConfig> entry : containerConfigs.entrySet()) {
+            ContainerConfig sc = entry.getValue();
+            result.add(String.format("%s: %s", sc.getContainerName(), sc.getContainerFlowConfigs()));
+        }
+        return result;
+    }
+
+    public List<String> psd() {
+        List<String> result = new ArrayList<String>();
+        for (String containerName : containerData.keySet()) {
+            ContainerData sd = containerData.get(containerName);
+            for (Node sid : sd.getSwPorts().keySet()) {
+                Set<NodeConnector> s = sd.getSwPorts().get(sid);
+                result.add("\t" + sid + " : " + s);
+            }
+
+            for (ContainerFlow s : sd.getContainerFlowSpecs()) {
+                result.add("\t" + s.toString());
+            }
+        }
+        return result;
+    }
+
+    public List<String> psp() {
+        List<String> result = new ArrayList<String>();
+        for (NodeConnector sp : nodeConnectorToContainers.keySet()) {
+            result.add(nodeConnectorToContainers.get(sp).toString());
+        }
+        return result;
+    }
+
+    public List<String> psm() {
+        List<String> result = new ArrayList<String>();
+        for (Node sp : nodeToContainers.keySet()) {
+            result.add(nodeToContainers.get(sp).toString());
+        }
+        return result;
+    }
+
+    public List<String> addContainer(String arg1, String arg2) {
+        List<String> result = new ArrayList<String>();
+        String containerName = arg1;
+        if (containerName == null) {
+            result.add("Container Name not specified");
+            return result;
+        }
+        String staticVlan = arg2;
+        ContainerConfig containerConfig = new ContainerConfig(containerName, staticVlan, null, null);
+        result.add((this.addRemoveContainer(containerConfig, false)).toString());
+        return result;
+    }
+
+    public List<String> createContainer(String arg1, String arg2) {
+        List<String> result = new ArrayList<String>();
+        String containerName = arg1;
+        if (containerName == null) {
+            result.add("Container Name not specified");
+            return result;
+        }
+        String staticVlan = arg2;
+        if (staticVlan == null) {
+            result.add("Static Vlan not specified");
+            return result;
+        }
+        List<String> ports = new ArrayList<String>();
+        for (long l = 1L; l < 10L; l++) {
+            ports.add(NodeConnectorCreator.createOFNodeConnector((short) 1, NodeCreator.createOFNode(l)).toString());
+        }
+        List<ContainerFlowConfig> cFlowList = new ArrayList<ContainerFlowConfig>();
+        cFlowList.add(this.createSampleContainerFlowConfig("tcp", true));
+        ContainerConfig containerConfig = new ContainerConfig(containerName, staticVlan, ports, cFlowList);
+        result.add((this.addRemoveContainer(containerConfig, false)).toString());
+        return result;
+    }
+
+    public List<String> removeContainerShell(String arg1) {
+        List<String> result = new ArrayList<String>();
+        String containerName = arg1;
+        if (containerName == null) {
+            result.add("Container Name not specified");
+            return result;
+        }
+        ContainerConfig containerConfig = new ContainerConfig(containerName, "", null, null);
+        result.add((this.addRemoveContainer(containerConfig, true)).toString());
+        return result;
+    }
+
+    public List<String> addContainerEntry(String arg1, String arg2, String arg3) {
+        List<String> result = new ArrayList<String>();
+        String containerName = arg1;
+        if (containerName == null) {
+            result.add("Container Name not specified");
+            return result;
+        }
+        String nodeId = arg2;
+        if (nodeId == null) {
+            result.add("Node Id not specified");
+            return result;
+        }
+        String portId = arg3;
+        if (portId == null) {
+            result.add("Port not specified");
+            return result;
+        }
+        Node node = NodeCreator.createOFNode(Long.valueOf(nodeId));
+        Short port = Short.valueOf(portId);
+        NodeConnector nc = NodeConnectorCreator.createOFNodeConnector(port, node);
+        List<String> portList = new ArrayList<String>(1);
+        portList.add(nc.toString());
+        result.add((this.addRemoveContainerEntries(containerName, portList, false)).toString());
+        return result;
+    }
+
+    public List<String> removeContainerEntry(String arg1, String arg2, String arg3) {
+        List<String> result = new ArrayList<String>();
+        String containerName = arg1;
+        if (containerName == null) {
+            result.add("Container Name not specified");
+            return result;
+        }
+        String nodeId = arg2;
+        if (nodeId == null) {
+            result.add("Node Id not specified");
+            return result;
+        }
+        String portId = arg3;
+        if (portId == null) {
+            result.add("Port not specified");
+            return result;
+        }
+        Node node = NodeCreator.createOFNode(Long.valueOf(nodeId));
+        Short port = Short.valueOf(portId);
+        NodeConnector nc = NodeConnectorCreator.createOFNodeConnector(port, node);
+        List<String> portList = new ArrayList<String>(1);
+        portList.add(nc.toString());
+        result.add((this.addRemoveContainerEntries(containerName, portList, true)).toString());
+        return result;
+    }
+    public List<String> addContainerFlow(String arg1, String arg2, String arg3) {
+        List<String> result = new ArrayList<String>();
+        String containerName = arg1;
+        if (containerName == null) {
+            result.add("Container Name not specified");
+            return result;
+        }
+        String cflowName = arg2;
+        if (cflowName == null) {
+            result.add("cflowName not specified");
+            return result;
+        }
+        String unidirectional = arg3;
+        boolean boolUnidirectional = Boolean.parseBoolean(unidirectional);
+        List<ContainerFlowConfig> list = new ArrayList<ContainerFlowConfig>();
+        list.add(createSampleContainerFlowConfig(cflowName, boolUnidirectional));
+        result.add((this.addRemoveContainerFlow(containerName, list, false)).toString());
+        return result;
+    }
+
+    public List<String> removeContainerFlow(String arg1, String arg2) {
+        List<String> result = new ArrayList<String>();
+        String containerName = arg1;
+        if (containerName == null) {
+            result.add("Container Name not specified");
+            return result;
+        }
+        String cflowName = arg2;
+        if (cflowName == null) {
+            result.add("cflowName not specified");
+            return result;
+        }
+        Set<String> set = new HashSet<String>(1);
+        set.add(cflowName);
+        result.add((this.removeContainerFlows(containerName, set)).toString());
+        return result;
+    }
+
+    public List<String> containermgrGetRoles() {
+        List<String> result = new ArrayList<String>();
+        result.add("Configured roles for Container Mgr:");
+        List<String> list = this.getRoles();
+        for (String role : list) {
+            result.add(role + "\t" + roles.get(role));
+        }
+        return result;
+    }
+
+    public List<String> containermgrGetAuthorizedGroups(String arg1) {
+        List<String> result = new ArrayList<String>();
+        String roleName = arg1;
+        if (roleName == null || roleName.trim().isEmpty()) {
+            result.add("Invalid argument");
+            result.add("mmGetAuthorizedGroups <role_name>");
+            return result;
+        }
+        result.add("Resource Groups associated to role " + roleName + ":");
+        List<ResourceGroup> list = this.getAuthorizedGroups(roleName);
+        for (ResourceGroup group : list) {
+            result.add(group.toString());
+        }
+        return result;
+    }
+    public List<String> containermgrGetAuthorizedResources(String arg1) {
+        List<String> result = new ArrayList<String>();
+        String roleName = arg1;
+        if (roleName == null || roleName.trim().isEmpty()) {
+            result.add("Invalid argument");
+            result.add("mmGetAuthorizedResources <role_name>");
+            return result;
+        }
+        result.add("Resource associated to role " + roleName + ":");
+        List<Resource> list = this.getAuthorizedResources(roleName);
+        for (Resource resource : list) {
+            result.add(resource.toString());
+        }
+        return result;
+    }
+    public List<String> containermgrGetResourcesForGroup(String arg1) {
+        List<String> result = new ArrayList<String>();
+        String groupName = arg1;
+        if (groupName == null || groupName.trim().isEmpty()) {
+            result.add("Invalid argument");
+            result.add("containermgrResourcesForGroup <group_name>");
+            return result;
+        }
+        result.add("Group " + groupName + " contains the following resources:");
+        List<Object> resources = this.getResources(groupName);
+        for (Object resource : resources) {
+            result.add(resource.toString());
+        }
+        return result;
+    }
+    public List<String> containermgrGetUserLevel(String arg1) {
+        List<String> result = new ArrayList<String>();
+        String userName = arg1;
+        if (userName == null || userName.trim().isEmpty()) {
+            result.add("Invalid argument");
+            result.add("containermgrGetUserLevel <user_name>");
+            return result;
+        }
+        result.add("User " + userName + " has level: " + this.getUserLevel(userName));
+        return result;
+    }
+    public List<String> containermgrGetUserResources(String arg1) {
+        List<String> result = new ArrayList<String>();
+        String userName = arg1;
+        if (userName == null || userName.trim().isEmpty()) {
+            result.add("Invalid argument");
+            result.add("containermgrGetUserResources <user_name>");
+            return result;
+        }
+        result.add("User " + userName + " owns the following resources: ");
+        Set<Resource> resources = this.getAllResourcesforUser(userName);
+        for (Resource resource : resources) {
+            result.add(resource.toString());
+        }
+        return result;
+    }
+    public List<String> saveConfig() {
+        List<String> result = new ArrayList<String>();
+        Status status = new Status(StatusCode.NOSERVICE, "Configuration service not reachable");
+
+        IConfigurationService configService = (IConfigurationService) ServiceHelper.getGlobalInstance(
+                IConfigurationService.class, this);
+        if (configService != null) {
+            status = configService.saveConfigurations();
+        }
+        result.add(status.toString());
+        return result;
+    }
 }
diff --git a/opendaylight/containermanager/shell/pom.xml b/opendaylight/containermanager/shell/pom.xml
new file mode 100644 (file)
index 0000000..1eedd4b
--- /dev/null
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.opendaylight.controller</groupId>
+    <artifactId>commons.opendaylight</artifactId>
+    <version>1.4.2-SNAPSHOT</version>
+    <relativePath>../../commons/opendaylight</relativePath>
+  </parent>
+  <artifactId>containermanager.shell</artifactId>
+  <version>${containermanager.shell.version}</version>
+  <packaging>bundle</packaging>
+  <dependencies>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.karaf.shell</groupId>
+      <artifactId>org.apache.karaf.shell.console</artifactId>
+      <version>${karaf.shell.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.mockito</groupId>
+      <artifactId>mockito-all</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>containermanager</artifactId>
+      <version>${containermanager.version}</version>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <version>${bundle.plugin.version}</version>
+        <configuration>
+          <instructions>
+            <Import-Package>org.apache.felix.service.command,
+              org.apache.karaf.shell.commands,
+              org.apache.karaf.shell.console,
+              *</Import-Package>
+          </instructions>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+
+</project>
diff --git a/opendaylight/containermanager/shell/src/main/java/org/opendaylight/controller/containermanager/shell/AddContainer.java b/opendaylight/containermanager/shell/src/main/java/org/opendaylight/controller/containermanager/shell/AddContainer.java
new file mode 100644 (file)
index 0000000..e87682e
--- /dev/null
@@ -0,0 +1,29 @@
+package org.opendaylight.controller.containermanager.shell;
+
+import org.apache.felix.gogo.commands.Command;
+import org.apache.felix.gogo.commands.Argument;
+import org.apache.karaf.shell.console.OsgiCommandSupport;
+import org.opendaylight.controller.containermanager.IContainerManagerShell;
+
+@Command(scope = "containermanager", name = "addcontainer", description="Add Container")
+public class AddContainer extends OsgiCommandSupport{
+    private IContainerManagerShell containerManager;
+
+    @Argument(index=0, name="containerName", description="container name", required=true, multiValued=false)
+    String containerName = null;
+
+    @Argument(index=1, name="staticVlan", description="staticVlan", required=true, multiValued=false)
+    String staticVlan = null;
+
+    @Override
+    protected Object doExecute() throws Exception {
+        for(String p : containerManager.addContainer(containerName, staticVlan)) {
+            System.out.println(p);
+        }
+        return null;
+    }
+
+    public void setContainerManager(IContainerManagerShell containerManager){
+        this.containerManager = containerManager;
+    }
+}
\ No newline at end of file
diff --git a/opendaylight/containermanager/shell/src/main/java/org/opendaylight/controller/containermanager/shell/AddContainerEntry.java b/opendaylight/containermanager/shell/src/main/java/org/opendaylight/controller/containermanager/shell/AddContainerEntry.java
new file mode 100644 (file)
index 0000000..b7ee4bd
--- /dev/null
@@ -0,0 +1,32 @@
+package org.opendaylight.controller.containermanager.shell;
+
+import org.apache.felix.gogo.commands.Command;
+import org.apache.felix.gogo.commands.Argument;
+import org.apache.karaf.shell.console.OsgiCommandSupport;
+import org.opendaylight.controller.containermanager.IContainerManagerShell;
+
+@Command(scope = "containermanager", name = "AddContainerEntry", description="add container entry")
+public class AddContainerEntry extends OsgiCommandSupport{
+    private IContainerManagerShell containerManager;
+
+    @Argument(index=0, name="containerName", description="container name", required=true, multiValued=false)
+    String containerName = null;
+
+    @Argument(index=1, name="nodeId", description="node ID", required=true, multiValued=false)
+    String nodeId = null;
+
+    @Argument(index=2, name="portId", description="portId", required=true, multiValued=false)
+    String portId = null;
+
+    @Override
+    protected Object doExecute() throws Exception {
+        for(String p : containerManager.addContainerEntry(containerName, nodeId, portId)) {
+            System.out.println(p);
+        }
+        return null;
+    }
+
+    public void setContainerManager(IContainerManagerShell containerManager){
+        this.containerManager = containerManager;
+    }
+}
\ No newline at end of file
diff --git a/opendaylight/containermanager/shell/src/main/java/org/opendaylight/controller/containermanager/shell/AddContainerFlow.java b/opendaylight/containermanager/shell/src/main/java/org/opendaylight/controller/containermanager/shell/AddContainerFlow.java
new file mode 100644 (file)
index 0000000..03ed94d
--- /dev/null
@@ -0,0 +1,32 @@
+package org.opendaylight.controller.containermanager.shell;
+
+import org.apache.felix.gogo.commands.Command;
+import org.apache.felix.gogo.commands.Argument;
+import org.apache.karaf.shell.console.OsgiCommandSupport;
+import org.opendaylight.controller.containermanager.IContainerManagerShell;
+
+@Command(scope = "containermanager", name = "addContainerFlow", description="adds container flow")
+public class AddContainerFlow extends OsgiCommandSupport{
+    private IContainerManagerShell containerManager;
+
+    @Argument(index=0, name="containerName", description="container name", required=true, multiValued=false)
+    String containerName = null;
+
+    @Argument(index=1, name="cflowName", description="c Flow name", required=true, multiValued=false)
+    String cflowName = null;
+
+    @Argument(index=2, name="unidirectional", description="unidirectional", required=true, multiValued=false)
+    String unidirectional = null;
+
+    @Override
+    protected Object doExecute() throws Exception {
+        for(String p : containerManager.addContainerFlow(containerName, cflowName, unidirectional)) {
+            System.out.println(p);
+        }
+        return null;
+    }
+
+    public void setContainerManager(IContainerManagerShell containerManager){
+        this.containerManager = containerManager;
+    }
+}
\ No newline at end of file
diff --git a/opendaylight/containermanager/shell/src/main/java/org/opendaylight/controller/containermanager/shell/ContainermgrGetAuthorizedGroups.java b/opendaylight/containermanager/shell/src/main/java/org/opendaylight/controller/containermanager/shell/ContainermgrGetAuthorizedGroups.java
new file mode 100644 (file)
index 0000000..f78b856
--- /dev/null
@@ -0,0 +1,26 @@
+package org.opendaylight.controller.containermanager.shell;
+
+import org.apache.felix.gogo.commands.Command;
+import org.apache.felix.gogo.commands.Argument;
+import org.apache.karaf.shell.console.OsgiCommandSupport;
+import org.opendaylight.controller.containermanager.IContainerManagerShell;
+
+@Command(scope = "containermanager", name = "containermgrGetAuthorizedGroups", description="Get authorized groups")
+public class ContainermgrGetAuthorizedGroups extends OsgiCommandSupport{
+    private IContainerManagerShell containerManager;
+
+    @Argument(index=0, name="roleName", description="role name", required=true, multiValued=false)
+    String roleName = null;
+
+    @Override
+    protected Object doExecute() throws Exception {
+        for(String p : containerManager.containermgrGetAuthorizedGroups(roleName)) {
+            System.out.println(p);
+        }
+        return null;
+    }
+
+    public void setContainerManager(IContainerManagerShell containerManager){
+        this.containerManager = containerManager;
+    }
+}
\ No newline at end of file
diff --git a/opendaylight/containermanager/shell/src/main/java/org/opendaylight/controller/containermanager/shell/ContainermgrGetAuthorizedResources.java b/opendaylight/containermanager/shell/src/main/java/org/opendaylight/controller/containermanager/shell/ContainermgrGetAuthorizedResources.java
new file mode 100644 (file)
index 0000000..1ac50fa
--- /dev/null
@@ -0,0 +1,26 @@
+package org.opendaylight.controller.containermanager.shell;
+
+import org.apache.felix.gogo.commands.Command;
+import org.apache.felix.gogo.commands.Argument;
+import org.apache.karaf.shell.console.OsgiCommandSupport;
+import org.opendaylight.controller.containermanager.IContainerManagerShell;
+
+@Command(scope = "containermanager", name = "containermgrGetAuthorizedResources", description="Get authorized resources")
+public class ContainermgrGetAuthorizedResources extends OsgiCommandSupport{
+    private IContainerManagerShell containerManager;
+
+    @Argument(index=0, name="roleName", description="role name", required=true, multiValued=false)
+    String roleName = null;
+
+    @Override
+    protected Object doExecute() throws Exception {
+        for(String p : containerManager.containermgrGetAuthorizedResources(roleName)) {
+            System.out.println(p);
+        }
+        return null;
+    }
+
+    public void setContainerManager(IContainerManagerShell containerManager){
+        this.containerManager = containerManager;
+    }
+}
\ No newline at end of file
diff --git a/opendaylight/containermanager/shell/src/main/java/org/opendaylight/controller/containermanager/shell/ContainermgrGetResourcesForGroup.java b/opendaylight/containermanager/shell/src/main/java/org/opendaylight/controller/containermanager/shell/ContainermgrGetResourcesForGroup.java
new file mode 100644 (file)
index 0000000..bbccb65
--- /dev/null
@@ -0,0 +1,26 @@
+package org.opendaylight.controller.containermanager.shell;
+
+import org.apache.felix.gogo.commands.Command;
+import org.apache.felix.gogo.commands.Argument;
+import org.apache.karaf.shell.console.OsgiCommandSupport;
+import org.opendaylight.controller.containermanager.IContainerManagerShell;
+
+@Command(scope = "containermanager", name = "containermgrGetResourcesForGroup", description="Get resources for group")
+public class ContainermgrGetResourcesForGroup extends OsgiCommandSupport{
+    private IContainerManagerShell containerManager;
+
+    @Argument(index=0, name="groupName", description="group name", required=true, multiValued=false)
+    String groupName = null;
+
+    @Override
+    protected Object doExecute() throws Exception {
+        for(String p : containerManager.containermgrGetResourcesForGroup(groupName)) {
+            System.out.println(p);
+        }
+        return null;
+    }
+
+    public void setContainerManager(IContainerManagerShell containerManager){
+        this.containerManager = containerManager;
+    }
+}
\ No newline at end of file
diff --git a/opendaylight/containermanager/shell/src/main/java/org/opendaylight/controller/containermanager/shell/ContainermgrGetRoles.java b/opendaylight/containermanager/shell/src/main/java/org/opendaylight/controller/containermanager/shell/ContainermgrGetRoles.java
new file mode 100644 (file)
index 0000000..38fdb27
--- /dev/null
@@ -0,0 +1,22 @@
+package org.opendaylight.controller.containermanager.shell;
+
+import org.apache.felix.gogo.commands.Command;
+import org.apache.karaf.shell.console.OsgiCommandSupport;
+import org.opendaylight.controller.containermanager.IContainerManagerShell;
+
+@Command(scope = "containermanager", name = "containermgrGetRoles", description="Get container mgr roles")
+public class ContainermgrGetRoles extends OsgiCommandSupport{
+    private IContainerManagerShell containerManager;
+
+    @Override
+    protected Object doExecute() throws Exception {
+        for(String p : containerManager.containermgrGetRoles()) {
+            System.out.println(p);
+        }
+        return null;
+    }
+
+    public void setContainerManager(IContainerManagerShell containerManager){
+        this.containerManager = containerManager;
+    }
+}
\ No newline at end of file
diff --git a/opendaylight/containermanager/shell/src/main/java/org/opendaylight/controller/containermanager/shell/ContainermgrGetUserLevel.java b/opendaylight/containermanager/shell/src/main/java/org/opendaylight/controller/containermanager/shell/ContainermgrGetUserLevel.java
new file mode 100644 (file)
index 0000000..9ee607a
--- /dev/null
@@ -0,0 +1,26 @@
+package org.opendaylight.controller.containermanager.shell;
+
+import org.apache.felix.gogo.commands.Command;
+import org.apache.felix.gogo.commands.Argument;
+import org.apache.karaf.shell.console.OsgiCommandSupport;
+import org.opendaylight.controller.containermanager.IContainerManagerShell;
+
+@Command(scope = "containermanager", name = "containermgrGetUserLevel", description="Get user level")
+public class ContainermgrGetUserLevel extends OsgiCommandSupport{
+    private IContainerManagerShell containerManager;
+
+    @Argument(index=0, name="userName", description="user name", required=true, multiValued=false)
+    String userName = null;
+
+    @Override
+    protected Object doExecute() throws Exception {
+        for(String p : containerManager.containermgrGetUserLevel(userName)) {
+            System.out.println(p);
+        }
+        return null;
+    }
+
+    public void setContainerManager(IContainerManagerShell containerManager){
+        this.containerManager = containerManager;
+    }
+}
\ No newline at end of file
diff --git a/opendaylight/containermanager/shell/src/main/java/org/opendaylight/controller/containermanager/shell/ContainermgrGetUserResources.java b/opendaylight/containermanager/shell/src/main/java/org/opendaylight/controller/containermanager/shell/ContainermgrGetUserResources.java
new file mode 100644 (file)
index 0000000..6a281bd
--- /dev/null
@@ -0,0 +1,26 @@
+package org.opendaylight.controller.containermanager.shell;
+
+import org.apache.felix.gogo.commands.Command;
+import org.apache.felix.gogo.commands.Argument;
+import org.apache.karaf.shell.console.OsgiCommandSupport;
+import org.opendaylight.controller.containermanager.IContainerManagerShell;
+
+@Command(scope = "containermanager", name = "containermgrGetUserResources", description="Get user resources")
+public class ContainermgrGetUserResources extends OsgiCommandSupport{
+    private IContainerManagerShell containerManager;
+
+    @Argument(index=0, name="userName", description="user name", required=true, multiValued=false)
+    String userName = null;
+
+    @Override
+    protected Object doExecute() throws Exception {
+        for(String p : containerManager.containermgrGetUserResources(userName)) {
+            System.out.println(p);
+        }
+        return null;
+    }
+
+    public void setContainerManager(IContainerManagerShell containerManager){
+        this.containerManager = containerManager;
+    }
+}
\ No newline at end of file
diff --git a/opendaylight/containermanager/shell/src/main/java/org/opendaylight/controller/containermanager/shell/CreateContainer.java b/opendaylight/containermanager/shell/src/main/java/org/opendaylight/controller/containermanager/shell/CreateContainer.java
new file mode 100644 (file)
index 0000000..ef51563
--- /dev/null
@@ -0,0 +1,29 @@
+package org.opendaylight.controller.containermanager.shell;
+
+import org.apache.felix.gogo.commands.Command;
+import org.apache.felix.gogo.commands.Argument;
+import org.apache.karaf.shell.console.OsgiCommandSupport;
+import org.opendaylight.controller.containermanager.IContainerManagerShell;
+
+@Command(scope = "containermanager", name = "createcontainer", description="create container")
+public class CreateContainer extends OsgiCommandSupport{
+    private IContainerManagerShell containerManager;
+
+    @Argument(index=0, name="containerName", description="container name", required=true, multiValued=false)
+    String containerName = null;
+
+    @Argument(index=1, name="staticVlan", description="staticVlan", required=true, multiValued=false)
+    String staticVlan = null;
+
+    @Override
+    protected Object doExecute() throws Exception {
+        for(String p : containerManager.createContainer(containerName, staticVlan)) {
+            System.out.println(p);
+        }
+        return null;
+    }
+
+    public void setContainerManager(IContainerManagerShell containerManager){
+        this.containerManager = containerManager;
+    }
+}
\ No newline at end of file
diff --git a/opendaylight/containermanager/shell/src/main/java/org/opendaylight/controller/containermanager/shell/Pfc.java b/opendaylight/containermanager/shell/src/main/java/org/opendaylight/controller/containermanager/shell/Pfc.java
new file mode 100644 (file)
index 0000000..62b4c9a
--- /dev/null
@@ -0,0 +1,22 @@
+package org.opendaylight.controller.containermanager.shell;
+
+import org.apache.felix.gogo.commands.Command;
+import org.apache.karaf.shell.console.OsgiCommandSupport;
+import org.opendaylight.controller.containermanager.IContainerManagerShell;
+
+@Command(scope = "containermanager", name = "pfc", description="Display pfc")
+public class Pfc extends OsgiCommandSupport{
+    private IContainerManagerShell containerManager;
+
+    @Override
+    protected Object doExecute() throws Exception {
+        for(String p : containerManager.pfc()) {
+            System.out.println(p);
+        }
+        return null;
+    }
+
+    public void setContainerManager(IContainerManagerShell containerManager){
+        this.containerManager = containerManager;
+    }
+}
\ No newline at end of file
diff --git a/opendaylight/containermanager/shell/src/main/java/org/opendaylight/controller/containermanager/shell/Psc.java b/opendaylight/containermanager/shell/src/main/java/org/opendaylight/controller/containermanager/shell/Psc.java
new file mode 100644 (file)
index 0000000..83e6496
--- /dev/null
@@ -0,0 +1,22 @@
+package org.opendaylight.controller.containermanager.shell;
+
+import org.apache.felix.gogo.commands.Command;
+import org.apache.karaf.shell.console.OsgiCommandSupport;
+import org.opendaylight.controller.containermanager.IContainerManagerShell;
+
+@Command(scope = "containermanager", name = "psc", description="Display ")
+public class Psc extends OsgiCommandSupport{
+    private IContainerManagerShell containerManager;
+
+    @Override
+    protected Object doExecute() throws Exception {
+        for(String p : containerManager.psc()) {
+            System.out.println(p);
+        }
+        return null;
+    }
+
+    public void setContainerManager(IContainerManagerShell containerManager){
+        this.containerManager = containerManager;
+    }
+}
\ No newline at end of file
diff --git a/opendaylight/containermanager/shell/src/main/java/org/opendaylight/controller/containermanager/shell/Psd.java b/opendaylight/containermanager/shell/src/main/java/org/opendaylight/controller/containermanager/shell/Psd.java
new file mode 100644 (file)
index 0000000..ff8a024
--- /dev/null
@@ -0,0 +1,22 @@
+package org.opendaylight.controller.containermanager.shell;
+
+import org.apache.felix.gogo.commands.Command;
+import org.apache.karaf.shell.console.OsgiCommandSupport;
+import org.opendaylight.controller.containermanager.IContainerManagerShell;
+
+@Command(scope = "containermanager", name = "psd", description="Display psd")
+public class Psd extends OsgiCommandSupport{
+    private IContainerManagerShell containerManager;
+
+    @Override
+    protected Object doExecute() throws Exception {
+        for(String p : containerManager.psd()) {
+            System.out.println(p);
+        }
+        return null;
+    }
+
+    public void setContainerManager(IContainerManagerShell containerManager){
+        this.containerManager = containerManager;
+    }
+}
\ No newline at end of file
diff --git a/opendaylight/containermanager/shell/src/main/java/org/opendaylight/controller/containermanager/shell/Psm.java b/opendaylight/containermanager/shell/src/main/java/org/opendaylight/controller/containermanager/shell/Psm.java
new file mode 100644 (file)
index 0000000..a7c3549
--- /dev/null
@@ -0,0 +1,22 @@
+package org.opendaylight.controller.containermanager.shell;
+
+import org.apache.felix.gogo.commands.Command;
+import org.apache.karaf.shell.console.OsgiCommandSupport;
+import org.opendaylight.controller.containermanager.IContainerManagerShell;
+
+@Command(scope = "containermanager", name = "psm", description="Display psm")
+public class Psm extends OsgiCommandSupport{
+    private IContainerManagerShell containerManager;
+
+    @Override
+    protected Object doExecute() throws Exception {
+        for(String p : containerManager.psm()) {
+            System.out.println(p);
+        }
+        return null;
+    }
+
+    public void setContainerManager(IContainerManagerShell containerManager){
+        this.containerManager = containerManager;
+    }
+}
\ No newline at end of file
diff --git a/opendaylight/containermanager/shell/src/main/java/org/opendaylight/controller/containermanager/shell/Psp.java b/opendaylight/containermanager/shell/src/main/java/org/opendaylight/controller/containermanager/shell/Psp.java
new file mode 100644 (file)
index 0000000..d221c83
--- /dev/null
@@ -0,0 +1,22 @@
+package org.opendaylight.controller.containermanager.shell;
+
+import org.apache.felix.gogo.commands.Command;
+import org.apache.karaf.shell.console.OsgiCommandSupport;
+import org.opendaylight.controller.containermanager.IContainerManagerShell;
+
+@Command(scope = "containermanager", name = "psp", description="Display psp")
+public class Psp extends OsgiCommandSupport{
+    private IContainerManagerShell containerManager;
+
+    @Override
+    protected Object doExecute() throws Exception {
+        for(String p : containerManager.psp()) {
+            System.out.println(p);
+        }
+        return null;
+    }
+
+    public void setContainerManager(IContainerManagerShell containerManager){
+        this.containerManager = containerManager;
+    }
+}
\ No newline at end of file
diff --git a/opendaylight/containermanager/shell/src/main/java/org/opendaylight/controller/containermanager/shell/RemoveContainer.java b/opendaylight/containermanager/shell/src/main/java/org/opendaylight/controller/containermanager/shell/RemoveContainer.java
new file mode 100644 (file)
index 0000000..997ef67
--- /dev/null
@@ -0,0 +1,26 @@
+package org.opendaylight.controller.containermanager.shell;
+
+import org.apache.felix.gogo.commands.Command;
+import org.apache.felix.gogo.commands.Argument;
+import org.apache.karaf.shell.console.OsgiCommandSupport;
+import org.opendaylight.controller.containermanager.IContainerManagerShell;
+
+@Command(scope = "containermanager", name = "removecontainer", description="remove container")
+public class RemoveContainer extends OsgiCommandSupport{
+    private IContainerManagerShell containerManager;
+
+    @Argument(index=0, name="containerName", description="container name", required=true, multiValued=false)
+    String containerName = null;
+
+    @Override
+    protected Object doExecute() throws Exception {
+        for(String p : containerManager.removeContainerShell(containerName)) {
+            System.out.println(p);
+        }
+        return null;
+    }
+
+    public void setContainerManager(IContainerManagerShell containerManager){
+        this.containerManager = containerManager;
+    }
+}
\ No newline at end of file
diff --git a/opendaylight/containermanager/shell/src/main/java/org/opendaylight/controller/containermanager/shell/RemoveContainerEntry.java b/opendaylight/containermanager/shell/src/main/java/org/opendaylight/controller/containermanager/shell/RemoveContainerEntry.java
new file mode 100644 (file)
index 0000000..9413842
--- /dev/null
@@ -0,0 +1,32 @@
+package org.opendaylight.controller.containermanager.shell;
+
+import org.apache.felix.gogo.commands.Command;
+import org.apache.felix.gogo.commands.Argument;
+import org.apache.karaf.shell.console.OsgiCommandSupport;
+import org.opendaylight.controller.containermanager.IContainerManagerShell;
+
+@Command(scope = "containermanager", name = "removeContainerEntry", description="remove container entry")
+public class RemoveContainerEntry extends OsgiCommandSupport{
+    private IContainerManagerShell containerManager;
+
+    @Argument(index=0, name="containerName", description="container name", required=true, multiValued=false)
+    String containerName = null;
+
+    @Argument(index=1, name="nodeId", description="node ID", required=true, multiValued=false)
+    String nodeId = null;
+
+    @Argument(index=2, name="portId", description="portId", required=true, multiValued=false)
+    String portId = null;
+
+    @Override
+    protected Object doExecute() throws Exception {
+        for(String p : containerManager.removeContainerEntry(containerName, nodeId, portId)) {
+            System.out.println(p);
+        }
+        return null;
+    }
+
+    public void setContainerManager(IContainerManagerShell containerManager){
+        this.containerManager = containerManager;
+    }
+}
\ No newline at end of file
diff --git a/opendaylight/containermanager/shell/src/main/java/org/opendaylight/controller/containermanager/shell/RemoveContainerFlow.java b/opendaylight/containermanager/shell/src/main/java/org/opendaylight/controller/containermanager/shell/RemoveContainerFlow.java
new file mode 100644 (file)
index 0000000..94cbb19
--- /dev/null
@@ -0,0 +1,29 @@
+package org.opendaylight.controller.containermanager.shell;
+
+import org.apache.felix.gogo.commands.Command;
+import org.apache.felix.gogo.commands.Argument;
+import org.apache.karaf.shell.console.OsgiCommandSupport;
+import org.opendaylight.controller.containermanager.IContainerManagerShell;
+
+@Command(scope = "containermanager", name = "removeContainerFlow", description="removes container flow")
+public class RemoveContainerFlow extends OsgiCommandSupport{
+    private IContainerManagerShell containerManager;
+
+    @Argument(index=0, name="containerName", description="container name", required=true, multiValued=false)
+    String containerName = null;
+
+    @Argument(index=1, name="cflowName", description="c Flow name", required=true, multiValued=false)
+    String cflowName = null;
+
+    @Override
+    protected Object doExecute() throws Exception {
+        for(String p : containerManager.removeContainerFlow(containerName, cflowName)) {
+            System.out.println(p);
+        }
+        return null;
+    }
+
+    public void setContainerManager(IContainerManagerShell containerManager){
+        this.containerManager = containerManager;
+    }
+}
\ No newline at end of file
diff --git a/opendaylight/containermanager/shell/src/main/java/org/opendaylight/controller/containermanager/shell/SaveConfig.java b/opendaylight/containermanager/shell/src/main/java/org/opendaylight/controller/containermanager/shell/SaveConfig.java
new file mode 100644 (file)
index 0000000..b96f769
--- /dev/null
@@ -0,0 +1,22 @@
+package org.opendaylight.controller.containermanager.shell;
+
+import org.apache.felix.gogo.commands.Command;
+import org.apache.karaf.shell.console.OsgiCommandSupport;
+import org.opendaylight.controller.containermanager.IContainerManagerShell;
+
+@Command(scope = "containermanager", name = "saveConfig", description="Save config")
+public class SaveConfig extends OsgiCommandSupport{
+    private IContainerManagerShell containerManager;
+
+    @Override
+    protected Object doExecute() throws Exception {
+        for(String p : containerManager.saveConfig()) {
+            System.out.println(p);
+        }
+        return null;
+    }
+
+    public void setContainerManager(IContainerManagerShell containerManager){
+        this.containerManager = containerManager;
+    }
+}
\ No newline at end of file
diff --git a/opendaylight/containermanager/shell/src/main/resources/OSGI-INF/blueprint/blueprint.xml b/opendaylight/containermanager/shell/src/main/resources/OSGI-INF/blueprint/blueprint.xml
new file mode 100644 (file)
index 0000000..e7e01f8
--- /dev/null
@@ -0,0 +1,123 @@
+<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
+
+    <reference id="containerManagerRef" interface="org.opendaylight.controller.containermanager.IContainerManagerShell"/>
+    <command-bundle xmlns="http://karaf.apache.org/xmlns/shell/v1.1.0">
+
+        <command>
+        <action class="org.opendaylight.controller.containermanager.shell.AddContainer">
+            <property name="containerManager" ref="containerManagerRef"/>
+            </action>
+        </command>
+
+        <command>
+        <action class="org.opendaylight.controller.containermanager.shell.AddContainerEntry">
+            <property name="containerManager" ref="containerManagerRef"/>
+            </action>
+        </command>
+
+        <command>
+        <action class="org.opendaylight.controller.containermanager.shell.AddContainerFlow">
+            <property name="containerManager" ref="containerManagerRef"/>
+            </action>
+        </command>
+
+        <command>
+        <action class="org.opendaylight.controller.containermanager.shell.ContainermgrGetAuthorizedGroups">
+            <property name="containerManager" ref="containerManagerRef"/>
+            </action>
+        </command>
+
+        <command>
+        <action class="org.opendaylight.controller.containermanager.shell.ContainermgrGetAuthorizedResources">
+            <property name="containerManager" ref="containerManagerRef"/>
+            </action>
+        </command>
+
+        <command>
+        <action class="org.opendaylight.controller.containermanager.shell.ContainermgrGetResourcesForGroup">
+            <property name="containerManager" ref="containerManagerRef"/>
+            </action>
+        </command>
+
+        <command>
+        <action class="org.opendaylight.controller.containermanager.shell.ContainermgrGetRoles">
+            <property name="containerManager" ref="containerManagerRef"/>
+            </action>
+        </command>
+
+        <command>
+        <action class="org.opendaylight.controller.containermanager.shell.ContainermgrGetUserLevel">
+            <property name="containerManager" ref="containerManagerRef"/>
+            </action>
+        </command>
+
+        <command>
+        <action class="org.opendaylight.controller.containermanager.shell.ContainermgrGetUserResources">
+            <property name="containerManager" ref="containerManagerRef"/>
+            </action>
+        </command>
+
+        <command>
+        <action class="org.opendaylight.controller.containermanager.shell.CreateContainer">
+            <property name="containerManager" ref="containerManagerRef"/>
+            </action>
+        </command>
+
+        <command>
+        <action class="org.opendaylight.controller.containermanager.shell.Pfc">
+            <property name="containerManager" ref="containerManagerRef"/>
+            </action>
+        </command>
+
+        <command>
+        <action class="org.opendaylight.controller.containermanager.shell.Psc">
+            <property name="containerManager" ref="containerManagerRef"/>
+            </action>
+        </command>
+
+        <command>
+        <action class="org.opendaylight.controller.containermanager.shell.Psd">
+            <property name="containerManager" ref="containerManagerRef"/>
+            </action>
+        </command>
+
+        <command>
+        <action class="org.opendaylight.controller.containermanager.shell.Psm">
+            <property name="containerManager" ref="containerManagerRef"/>
+            </action>
+        </command>
+
+        <command>
+        <action class="org.opendaylight.controller.containermanager.shell.Psp">
+            <property name="containerManager" ref="containerManagerRef"/>
+            </action>
+        </command>
+
+        <command>
+        <action class="org.opendaylight.controller.containermanager.shell.RemoveContainer">
+            <property name="containerManager" ref="containerManagerRef"/>
+            </action>
+        </command>
+
+        <command>
+        <action class="org.opendaylight.controller.containermanager.shell.RemoveContainerEntry">
+            <property name="containerManager" ref="containerManagerRef"/>
+            </action>
+        </command>
+
+        <command>
+        <action class="org.opendaylight.controller.containermanager.shell.RemoveContainerFlow">
+            <property name="containerManager" ref="containerManagerRef"/>
+            </action>
+        </command>
+
+        <command>
+        <action class="org.opendaylight.controller.containermanager.shell.SaveConfig">
+            <property name="containerManager" ref="containerManagerRef"/>
+            </action>
+        </command>
+
+    </command-bundle>
+
+
+</blueprint>
diff --git a/opendaylight/containermanager/shell/src/test/java/org/opendaylight/controller/containermanager/shell/ContainerManagerShellTest.java b/opendaylight/containermanager/shell/src/test/java/org/opendaylight/controller/containermanager/shell/ContainerManagerShellTest.java
new file mode 100644 (file)
index 0000000..f11d1da
--- /dev/null
@@ -0,0 +1,368 @@
+package org.opendaylight.controller.containermanager.shell;
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.lang.reflect.Field;
+
+import org.junit.Assert;
+import org.junit.Test;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import org.opendaylight.controller.containermanager.IContainerManagerShell;
+
+
+public class ContainerManagerShellTest {
+    private IContainerManagerShell containerManager;
+
+    @Test
+    public void testAddContainer() throws Exception {
+        String containerName = "test", staticVlan = "1234";
+        AddContainer addConTest = new AddContainer();
+        containerManager = mock(IContainerManagerShell.class);
+        List<String> result = new ArrayList<String>(Arrays.asList("status"));
+        List<String> result2 = new ArrayList<String>(Arrays.asList("Container Name not specified"));
+        when(containerManager.addContainer(containerName, staticVlan)).thenReturn(result);
+        when(containerManager.addContainer(null, null)).thenReturn(result2);
+
+        Field cNField = addConTest.getClass().getDeclaredField("containerName");
+        cNField.setAccessible(true);
+        Field sVField = addConTest.getClass().getDeclaredField("staticVlan");
+        sVField.setAccessible(true);
+
+        cNField.set(addConTest, "test");
+        sVField.set(addConTest, "1234");
+
+        addConTest.setContainerManager(containerManager);
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        System.setOut(new PrintStream(baos));
+        addConTest.doExecute();
+        Assert.assertEquals("status\n", baos.toString());
+        baos.reset();
+
+        cNField.set(addConTest, null);
+        sVField.set(addConTest, null);
+        addConTest.doExecute();
+        Assert.assertEquals("Container Name not specified\n", baos.toString());
+    }
+
+    @Test
+    public void testAddContainerEntry() throws Exception {
+        String containerName = "test", nodeId = "1234", portId = "5678";
+        AddContainerEntry addConEntTest = new AddContainerEntry();
+        containerManager = mock(IContainerManagerShell.class);
+        List<String> result = new ArrayList<String>(Arrays.asList("status"));
+        when(containerManager.addContainerEntry(containerName, nodeId, portId)).thenReturn(result);
+
+        Field cNField = addConEntTest.getClass().getDeclaredField("containerName");
+        cNField.setAccessible(true);
+        Field nIField = addConEntTest.getClass().getDeclaredField("nodeId");
+        nIField.setAccessible(true);
+        Field pIField = addConEntTest.getClass().getDeclaredField("portId");
+        pIField.setAccessible(true);
+
+        cNField.set(addConEntTest, "test");
+        nIField.set(addConEntTest, "1234");
+        pIField.set(addConEntTest, "5678");
+
+        addConEntTest.setContainerManager(containerManager);
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        System.setOut(new PrintStream(baos));
+        addConEntTest.doExecute();
+        Assert.assertEquals("status\n", baos.toString());
+    }
+
+    @Test
+    public void testAddContainerFlow() throws Exception {
+        String containerName = "test", cflowName = "1234", unidirectional = "5678";
+        AddContainerFlow addConFlowTest = new AddContainerFlow();
+        containerManager = mock(IContainerManagerShell.class);
+        List<String> result = new ArrayList<String>(Arrays.asList("status"));
+        when(containerManager.addContainerFlow(containerName, cflowName, unidirectional)).thenReturn(result);
+
+        Field cNField = addConFlowTest.getClass().getDeclaredField("containerName");
+        cNField.setAccessible(true);
+        Field cfField = addConFlowTest.getClass().getDeclaredField("cflowName");
+        cfField.setAccessible(true);
+        Field unField = addConFlowTest.getClass().getDeclaredField("unidirectional");
+        unField.setAccessible(true);
+
+        cNField.set(addConFlowTest, "test");
+        cfField.set(addConFlowTest, "1234");
+        unField.set(addConFlowTest, "5678");
+
+        addConFlowTest.setContainerManager(containerManager);
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        System.setOut(new PrintStream(baos));
+        addConFlowTest.doExecute();
+        Assert.assertEquals("status\n", baos.toString());
+    }
+
+    @Test
+    public void testContainermgrGetAuthorizedGroups() throws Exception {
+        String roleName = "test";
+        ContainermgrGetAuthorizedGroups contmgrGTest = new ContainermgrGetAuthorizedGroups();
+        containerManager = mock(IContainerManagerShell.class);
+        List<String> result = new ArrayList<String>(Arrays.asList("status"));
+        when(containerManager.containermgrGetAuthorizedGroups(roleName)).thenReturn(result);
+
+        Field rNField = contmgrGTest.getClass().getDeclaredField("roleName");
+        rNField.setAccessible(true);
+
+        rNField.set(contmgrGTest, "test");
+
+        contmgrGTest.setContainerManager(containerManager);
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        System.setOut(new PrintStream(baos));
+        contmgrGTest.doExecute();
+        Assert.assertEquals("status\n", baos.toString());
+    }
+
+    @Test
+    public void testContainermgrGetAuthorizedResources() throws Exception {
+        String roleName = "test";
+        ContainermgrGetAuthorizedResources contmgrRTest = new ContainermgrGetAuthorizedResources();
+        containerManager = mock(IContainerManagerShell.class);
+        List<String> result = new ArrayList<String>(Arrays.asList("status"));
+        when(containerManager.containermgrGetAuthorizedResources(roleName)).thenReturn(result);
+
+        Field rNField = contmgrRTest.getClass().getDeclaredField("roleName");
+        rNField.setAccessible(true);
+
+        rNField.set(contmgrRTest, "test");
+
+        contmgrRTest.setContainerManager(containerManager);
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        System.setOut(new PrintStream(baos));
+        contmgrRTest.doExecute();
+        Assert.assertEquals("status\n", baos.toString());
+    }
+
+    @Test
+    public void testContainermgrGetResourcesForGroup() throws Exception {
+        String groupName = "test";
+        ContainermgrGetResourcesForGroup contmgrRTest = new ContainermgrGetResourcesForGroup();
+        containerManager = mock(IContainerManagerShell.class);
+        List<String> result = new ArrayList<String>(Arrays.asList("status"));
+        when(containerManager.containermgrGetResourcesForGroup(groupName)).thenReturn(result);
+
+        Field gNField = contmgrRTest.getClass().getDeclaredField("groupName");
+        gNField.setAccessible(true);
+
+        gNField.set(contmgrRTest, groupName);
+
+        contmgrRTest.setContainerManager(containerManager);
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        System.setOut(new PrintStream(baos));
+        contmgrRTest.doExecute();
+        Assert.assertEquals("status\n", baos.toString());
+    }
+
+    @Test
+    public void testContainermgrGetRoles() throws Exception {
+        ContainermgrGetRoles contmgrRTest = new ContainermgrGetRoles();
+        containerManager = mock(IContainerManagerShell.class);
+        List<String> result = new ArrayList<String>(Arrays.asList("status"));
+        when(containerManager.containermgrGetRoles()).thenReturn(result);
+
+        contmgrRTest.setContainerManager(containerManager);
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        System.setOut(new PrintStream(baos));
+        contmgrRTest.doExecute();
+        Assert.assertEquals("status\n", baos.toString());
+    }
+
+    @Test
+    public void testContainermgrGetUserLevel() throws Exception {
+        String userName = "test";
+        ContainermgrGetUserLevel contmgrUTest = new ContainermgrGetUserLevel();
+        containerManager = mock(IContainerManagerShell.class);
+        List<String> result = new ArrayList<String>(Arrays.asList("status"));
+        when(containerManager.containermgrGetUserLevel(userName)).thenReturn(result);
+
+        Field gNField = contmgrUTest.getClass().getDeclaredField("userName");
+        gNField.setAccessible(true);
+
+        gNField.set(contmgrUTest, userName);
+
+        contmgrUTest.setContainerManager(containerManager);
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        System.setOut(new PrintStream(baos));
+        contmgrUTest.doExecute();
+        Assert.assertEquals("status\n", baos.toString());
+    }
+
+    @Test
+    public void testContainermgrGetUserResources() throws Exception {
+        String userName = "test";
+        ContainermgrGetUserResources contmgrUTest = new ContainermgrGetUserResources();
+        containerManager = mock(IContainerManagerShell.class);
+        List<String> result = new ArrayList<String>(Arrays.asList("status"));
+        when(containerManager.containermgrGetUserResources(userName)).thenReturn(result);
+
+        Field gNField = contmgrUTest.getClass().getDeclaredField("userName");
+        gNField.setAccessible(true);
+
+        gNField.set(contmgrUTest, userName);
+
+        contmgrUTest.setContainerManager(containerManager);
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        System.setOut(new PrintStream(baos));
+        contmgrUTest.doExecute();
+        Assert.assertEquals("status\n", baos.toString());
+    }
+
+    @Test
+    public void testPfc() throws Exception {
+        Pfc pfc = new Pfc();
+        containerManager = mock(IContainerManagerShell.class);
+        List<String> result = new ArrayList<String>(Arrays.asList("status"));
+        when(containerManager.pfc()).thenReturn(result);
+
+        pfc.setContainerManager(containerManager);
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        System.setOut(new PrintStream(baos));
+        pfc.doExecute();
+        Assert.assertEquals("status\n", baos.toString());
+    }
+
+    @Test
+    public void testPsc() throws Exception {
+        Psc psc = new Psc();
+        containerManager = mock(IContainerManagerShell.class);
+        List<String> result = new ArrayList<String>(Arrays.asList("status"));
+        when(containerManager.psc()).thenReturn(result);
+
+        psc.setContainerManager(containerManager);
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        System.setOut(new PrintStream(baos));
+        psc.doExecute();
+        Assert.assertEquals("status\n", baos.toString());
+    }
+
+    @Test
+    public void testPsd() throws Exception {
+        Psd psd = new Psd();
+        containerManager = mock(IContainerManagerShell.class);
+        List<String> result = new ArrayList<String>(Arrays.asList("status"));
+        when(containerManager.psd()).thenReturn(result);
+
+        psd.setContainerManager(containerManager);
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        System.setOut(new PrintStream(baos));
+        psd.doExecute();
+        Assert.assertEquals("status\n", baos.toString());
+    }
+
+    @Test
+    public void testPsm() throws Exception {
+        Psm psm = new Psm();
+        containerManager = mock(IContainerManagerShell.class);
+        List<String> result = new ArrayList<String>(Arrays.asList("status"));
+        when(containerManager.psm()).thenReturn(result);
+
+        psm.setContainerManager(containerManager);
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        System.setOut(new PrintStream(baos));
+        psm.doExecute();
+        Assert.assertEquals("status\n", baos.toString());
+    }
+
+    @Test
+    public void testPsp() throws Exception {
+        Psp psp = new Psp();
+        containerManager = mock(IContainerManagerShell.class);
+        List<String> result = new ArrayList<String>(Arrays.asList("status"));
+        when(containerManager.psp()).thenReturn(result);
+
+        psp.setContainerManager(containerManager);
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        System.setOut(new PrintStream(baos));
+        psp.doExecute();
+        Assert.assertEquals("status\n", baos.toString());
+    }
+
+    @Test
+    public void testRemoveContainer() throws Exception {
+        String containerName = "test";
+        RemoveContainer remConTest = new RemoveContainer();
+        containerManager = mock(IContainerManagerShell.class);
+        List<String> result = new ArrayList<String>(Arrays.asList("status"));
+        when(containerManager.removeContainerShell(containerName)).thenReturn(result);
+
+        Field cNField = remConTest.getClass().getDeclaredField("containerName");
+        cNField.setAccessible(true);
+        cNField.set(remConTest, "test");
+
+        remConTest.setContainerManager(containerManager);
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        System.setOut(new PrintStream(baos));
+        remConTest.doExecute();
+        Assert.assertEquals("status\n", baos.toString());
+    }
+
+    @Test
+    public void testRemoveContainerEntry() throws Exception {
+        String containerName = "test", nodeId = "1234", portId = "5678";
+        RemoveContainerEntry remConEntTest = new RemoveContainerEntry();
+        containerManager = mock(IContainerManagerShell.class);
+        List<String> result = new ArrayList<String>(Arrays.asList("status"));
+        when(containerManager.removeContainerEntry(containerName, nodeId, portId)).thenReturn(result);
+
+        Field cNField = remConEntTest.getClass().getDeclaredField("containerName");
+        cNField.setAccessible(true);
+        Field nIField = remConEntTest.getClass().getDeclaredField("nodeId");
+        nIField.setAccessible(true);
+        Field pIField = remConEntTest.getClass().getDeclaredField("portId");
+        pIField.setAccessible(true);
+
+        cNField.set(remConEntTest, "test");
+        nIField.set(remConEntTest, "1234");
+        pIField.set(remConEntTest, "5678");
+
+        remConEntTest.setContainerManager(containerManager);
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        System.setOut(new PrintStream(baos));
+        remConEntTest.doExecute();
+        Assert.assertEquals("status\n", baos.toString());
+    }
+
+    @Test
+    public void testRemoveContainerFlow() throws Exception {
+        String containerName = "test", cflowName = "1234";
+        RemoveContainerFlow remConFlowTest = new RemoveContainerFlow();
+        containerManager = mock(IContainerManagerShell.class);
+        List<String> result = new ArrayList<String>(Arrays.asList("status"));
+        when(containerManager.removeContainerFlow(containerName, cflowName)).thenReturn(result);
+
+        Field cNField = remConFlowTest.getClass().getDeclaredField("containerName");
+        cNField.setAccessible(true);
+        Field cfField = remConFlowTest.getClass().getDeclaredField("cflowName");
+        cfField.setAccessible(true);
+
+        cNField.set(remConFlowTest, "test");
+        cfField.set(remConFlowTest, "1234");
+
+        remConFlowTest.setContainerManager(containerManager);
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        System.setOut(new PrintStream(baos));
+        remConFlowTest.doExecute();
+        Assert.assertEquals("status\n", baos.toString());
+    }
+
+    @Test
+    public void testSaveConfig() throws Exception {
+        SaveConfig saveConfig = new SaveConfig();
+        containerManager = mock(IContainerManagerShell.class);
+        List<String> result = new ArrayList<String>(Arrays.asList("status"));
+        when(containerManager.saveConfig()).thenReturn(result);
+
+        saveConfig.setContainerManager(containerManager);
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        System.setOut(new PrintStream(baos));
+        saveConfig.doExecute();
+        Assert.assertEquals("status\n", baos.toString());
+    }
+}
\ No newline at end of file
index 67c30454f86cc7b640c871b2e89955dda452262e..6a6a12d1de2499cb1956f02f456b158fd79f470e 100644 (file)
       <type>xml</type>
       <scope>runtime</scope>
     </dependency>
+    <!-- scope is compile so all features (there is only one) are installed
+            into startup.properties and the feature repo itself is not installed -->
     <dependency>
       <groupId>org.opendaylight.controller</groupId>
       <artifactId>base-features</artifactId>
       <version>${project.version}</version>
-      <type>kar</type>
+      <type>pom</type>
       <scope>runtime</scope>
     </dependency>
     <dependency>
index 6c1ca421c257ab81807c20f4a939d556cb5338c6..502e1a261c713b1ea030ec014e663dcb82f4b51b 100644 (file)
@@ -1,17 +1,11 @@
 # Extra packages to import from the boot class loader
 org.osgi.framework.system.packages.extra=org.apache.karaf.branding,sun.reflect,sun.reflect.misc,sun.misc,sun.nio.ch
 
-# https://bugs.eclipse.org/bugs/show_bug.cgi?id=325578
-# Extend the framework to avoid the resources to be presented with
-# a URL of type bundleresource: but to be presented as file:
-osgi.hook.configurators.include=org.eclipse.virgo.kernel.equinox.extensions.hooks.ExtensionsHookConfigurator
 
 # Embedded Tomcat configuration File
 org.eclipse.gemini.web.tomcat.config.path=configuration/tomcat-server.xml
 org.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH=true
 
-# Use Equinox as default OSGi Framework Implementation
-karaf.framework=equinox
 
 # Netconf startup configuration
 netconf.tcp.address=127.0.0.1
index ca8c83c380aea4f1c51c801a3e846a82e364fbeb..288fe629f806ff74a3c241a3d27e95a39e86fcf5 100644 (file)
@@ -7,7 +7,7 @@ mvn\:org.ops4j.pax.swissbox/pax-swissbox-bnd/1.7.0 = 5
 mvn\:org.ops4j.pax.url/pax-url-maven-commons/1.6.0 = 5
 mvn\:org.ops4j.pax.url/pax-url-aether/1.6.0 = 5
 mvn\:org.ops4j.pax.url/pax-url-wrap/1.6.0 = 5
-mvn\:javax.annotation/javax.annotation-api/1.2 = 5
+#mvn\:javax.annotation/javax.annotation-api/1.2 = 5
 mvn\:org.ops4j.pax.logging/pax-logging-api/1.7.2 = 8
 mvn\:org.ops4j.pax.logging/pax-logging-service/1.7.2 = 8
 mvn\:org.apache.karaf.service/org.apache.karaf.service.guard/3.0.1 = 10
diff --git a/opendaylight/distribution/opendaylight-karaf/src/main/resources/etc/system.properties b/opendaylight/distribution/opendaylight-karaf/src/main/resources/etc/system.properties
new file mode 100644 (file)
index 0000000..a312d66
--- /dev/null
@@ -0,0 +1,109 @@
+#
+# The properties defined in this file will be made available through system
+# properties at the very beginning of the Karaf's boot process.
+#
+
+# Use Equinox as default OSGi Framework Implementation
+karaf.framework=equinox
+
+# https://bugs.eclipse.org/bugs/show_bug.cgi?id=325578
+# Extend the framework to avoid the resources to be presented with
+# a URL of type bundleresource: but to be presented as file:
+osgi.hook.configurators.include=org.eclipse.virgo.kernel.equinox.extensions.hooks.ExtensionsHookConfigurator
+
+
+# Log level when the pax-logging service is not available
+# This level will only be used while the pax-logging service bundle
+# is not fully available.
+# To change log levels, please refer to the org.ops4j.pax.logging.cfg file
+# instead.
+org.ops4j.pax.logging.DefaultServiceLog.level = ERROR
+
+#
+# Name of this Karaf instance.
+#
+karaf.name = root
+
+#
+# Default repository where bundles will be loaded from before using
+# other Maven repositories.  For the full Maven configuration, see
+# the org.ops4j.pax.url.mvn.cfg file.
+#
+karaf.default.repository = system
+
+#
+# Location of a shell script that will be run when starting a shell
+# session.  This script can be used to create aliases and define
+# additional commands.
+#
+karaf.shell.init.script = ${karaf.etc}/shell.init.script
+
+#
+# Sets the maximum size of the shell command history. If not set,
+# defaults to 500 entries. Setting to 0 will disable history.
+#
+# karaf.shell.history.maxSize = 0
+
+#
+# Deletes the entire karaf.data directory at every start
+#
+karaf.clean.all = false
+
+#
+# Deletes the karaf.data/cache directory at every start
+#
+karaf.clean.cache = false
+
+#
+# Roles to use when logging into a local Karaf console.
+#
+# The syntax is the following:
+#   [classname:]principal
+# where classname is the class name of the principal object
+# (defaults to org.apache.karaf.jaas.modules.RolePrincipal)
+# and principal is the name of the principal of that class
+# (defaults to instance).
+#
+karaf.local.roles = admin,manager,viewer
+
+#
+# Set this empty property to avoid errors when validating xml documents.
+#
+xml.catalog.files =
+
+#
+# Suppress the bell in the console when hitting backspace too many times
+# for example
+#
+jline.nobell = true
+
+#
+# ServiceMix specs options
+#
+org.apache.servicemix.specs.debug = false
+org.apache.servicemix.specs.timeout = 0
+
+#
+# Settings for the OSGi 4.3 Weaving
+# By default, we will not weave any classes. Change this setting to include classes
+# that you application needs to have woven.
+#
+org.apache.aries.proxy.weaving.enabled = none
+# Classes not to weave - Aries default + Xerces which is known to have issues.
+org.apache.aries.proxy.weaving.disabled = org.objectweb.asm.*,org.slf4j.*,org.apache.log4j.*,javax.*,org.apache.xerces.*
+
+#
+# By default, only Karaf shell commands are secured, but additional services can be
+# secured by expanding this filter
+#
+karaf.secured.services = (&(osgi.command.scope=*)(osgi.command.function=*))
+
+#
+# Security properties
+#
+# To enable OSGi security, uncomment the properties below,
+# install the framework-security feature and restart.
+#
+#java.security.policy=${karaf.etc}/all.policy
+#org.osgi.framework.security=osgi
+#org.osgi.framework.trust.repositories=${karaf.etc}/trustStore.ks
index 9222734360a0b1cb81b58caafe36381728056048..8d4901d31b118659980148a20f79c0826b71a171 100644 (file)
         <groupId>org.apache.felix</groupId>
         <artifactId>maven-bundle-plugin</artifactId>
       </plugin>
-      <plugin>
-        <!-- FIXME: BUG-272: remove this configuration override -->
-        <!-- replaced with new configuration -->
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-checkstyle-plugin</artifactId>
-        <version>2.12</version>
-        <configuration>
-          <failsOnError>false</failsOnError>
-          <failOnViolation>false</failOnViolation>
-          <configLocation>checkstyle-logging.xml</configLocation>
-          <consoleOutput>true</consoleOutput>
-          <includeTestSourceDirectory>true</includeTestSourceDirectory>
-          <sourceDirectory>${project.basedir}</sourceDirectory>
-          <includes>**\/*.java,**\/*.xml,**\/*.ini,**\/*.sh,**\/*.bat,**\/*.yang</includes>
-          <excludes>**\/target\/,**\/bin\/,**\/target-ide\/,**\/${jmxGeneratorPath}\/,**\/${salGeneratorPath}\/</excludes>
-        </configuration>
-        <dependencies>
-          <dependency>
-            <groupId>org.opendaylight.yangtools</groupId>
-            <artifactId>checkstyle-logging</artifactId>
-            <version>${yangtools.version}</version>
-          </dependency>
-        </dependencies>
-        <executions>
-          <execution>
-            <goals>
-              <goal>check</goal>
-            </goals>
-          </execution>
-        </executions>
-      </plugin>
       <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-jar-plugin</artifactId>
diff --git a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/OptimisticLockFailedException.java b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/OptimisticLockFailedException.java
new file mode 100644 (file)
index 0000000..222289a
--- /dev/null
@@ -0,0 +1,34 @@
+package org.opendaylight.controller.md.sal.common.api.data;
+
+/**
+*
+* Failure of asynchronous transaction commit caused by failure
+* of optimistic locking.
+*
+* This exception is raised and returned when transaction commit
+* failed, because other transaction finished successfully
+* and modified same data as failed transaction.
+*
+*  Clients may recover from this error condition by
+*  retrieving current state and submitting new updated
+*  transaction.
+*
+*/
+public class OptimisticLockFailedException extends TransactionCommitFailedException {
+
+    private static final long serialVersionUID = 1L;
+
+    protected OptimisticLockFailedException(final String message, final Throwable cause, final boolean enableSuppression,
+            final boolean writableStackTrace) {
+        super(message, cause, enableSuppression, writableStackTrace);
+    }
+
+    public OptimisticLockFailedException(final String message, final Throwable cause) {
+        super(message, cause);
+    }
+
+    public OptimisticLockFailedException(final String message) {
+        super(message);
+    }
+
+}
diff --git a/opendaylight/md-sal/sal-distributed-datastore/pom.xml b/opendaylight/md-sal/sal-distributed-datastore/pom.xml
new file mode 100644 (file)
index 0000000..e7fcd83
--- /dev/null
@@ -0,0 +1,208 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.opendaylight.controller</groupId>
+    <artifactId>sal-parent</artifactId>
+    <version>1.1-SNAPSHOT</version>
+  </parent>
+  <artifactId>sal-distributed-datastore</artifactId>
+  <packaging>bundle</packaging>
+
+  <dependencies>
+    <dependency>
+      <groupId>com.google.guava</groupId>
+      <artifactId>guava</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>com.typesafe.akka</groupId>
+      <artifactId>akka-actor_${scala.version}</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>com.typesafe.akka</groupId>
+      <artifactId>akka-cluster_${scala.version}</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>com.typesafe.akka</groupId>
+      <artifactId>akka-persistence-experimental_${scala.version}</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>com.typesafe.akka</groupId>
+      <artifactId>akka-remote_${scala.version}</artifactId>
+    </dependency>
+
+    <!-- SAL Dependencies -->
+
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>config-api</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>sal-binding-api</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>sal-binding-config</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>sal-common-api</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>sal-common-util</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>sal-core-spi</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>org.opendaylight.yangtools</groupId>
+      <artifactId>concepts</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>org.opendaylight.yangtools</groupId>
+      <artifactId>yang-binding</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>org.opendaylight.yangtools</groupId>
+      <artifactId>yang-common</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>org.opendaylight.yangtools</groupId>
+      <artifactId>yang-data-api</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>org.osgi</groupId>
+      <artifactId>org.osgi.core</artifactId>
+    </dependency>
+
+    <!-- AKKA Dependencies -->
+    <dependency>
+      <groupId>org.scala-lang</groupId>
+      <artifactId>scala-library</artifactId>
+    </dependency>
+
+    <!-- Test Dependencies -->
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.mockito</groupId>
+      <artifactId>mockito-all</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-simple</artifactId>
+      <version>${slf4j.version}</version>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <extensions>true</extensions>
+        <configuration>
+          <instructions>
+            <Bundle-Name>${project.groupId}.${project.artifactId}</Bundle-Name>
+            <Export-package></Export-package>
+            <Private-Package></Private-Package>
+          </instructions>
+        </configuration>
+      </plugin>
+
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-jar-plugin</artifactId>
+        <executions>
+          <execution>
+            <goals>
+              <goal>test-jar</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
+        <groupId>org.jacoco</groupId>
+        <artifactId>jacoco-maven-plugin</artifactId>
+        <configuration>
+          <includes>
+            <include>org.opendaylight.controller.*</include>
+          </includes>
+          <check>false</check>
+        </configuration>
+        <executions>
+          <execution>
+            <id>pre-test</id>
+            <goals>
+              <goal>prepare-agent</goal>
+            </goals>
+          </execution>
+          <execution>
+            <id>post-test</id>
+            <goals>
+              <goal>report</goal>
+            </goals>
+            <phase>test</phase>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
+        <groupId>org.opendaylight.yangtools</groupId>
+        <artifactId>yang-maven-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>config</id>
+            <goals>
+              <goal>generate-sources</goal>
+            </goals>
+            <configuration>
+              <codeGenerators>
+                <generator>
+                  <codeGeneratorClass>org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator</codeGeneratorClass>
+                  <outputBaseDir>${jmxGeneratorPath}</outputBaseDir>
+                  <additionalConfiguration>
+                    <namespaceToPackage1>urn:opendaylight:params:xml:ns:yang:controller==org.opendaylight.controller.config.yang</namespaceToPackage1>
+                  </additionalConfiguration>
+                </generator>
+                <generator>
+                  <codeGeneratorClass>org.opendaylight.yangtools.maven.sal.api.gen.plugin.CodeGeneratorImpl</codeGeneratorClass>
+                  <outputBaseDir>${salGeneratorPath}</outputBaseDir>
+                </generator>
+              </codeGenerators>
+              <inspectDependencies>true</inspectDependencies>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+  <scm>
+    <connection>scm:git:ssh://git.opendaylight.org:29418/controller.git</connection>
+    <developerConnection>scm:git:ssh://git.opendaylight.org:29418/controller.git</developerConnection>
+    <tag>HEAD</tag>
+    <url>https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL:Architecture:Clustering</url>
+  </scm>
+</project>
diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DistributedDataStore.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DistributedDataStore.java
new file mode 100644 (file)
index 0000000..1bc554f
--- /dev/null
@@ -0,0 +1,43 @@
+package org.opendaylight.controller.cluster.datastore;
+
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeListener;
+import org.opendaylight.controller.sal.core.spi.data.DOMStore;
+import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadTransaction;
+import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadWriteTransaction;
+import org.opendaylight.controller.sal.core.spi.data.DOMStoreTransactionChain;
+import org.opendaylight.controller.sal.core.spi.data.DOMStoreWriteTransaction;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+/**
+ *
+ */
+public class DistributedDataStore implements DOMStore {
+
+    @Override
+    public <L extends AsyncDataChangeListener<InstanceIdentifier, NormalizedNode<?, ?>>> ListenerRegistration<L> registerChangeListener(InstanceIdentifier path, L listener, AsyncDataBroker.DataChangeScope scope) {
+        return new ListenerRegistrationProxy();
+    }
+
+    @Override
+    public DOMStoreTransactionChain createTransactionChain() {
+        return new TransactionChainProxy();
+    }
+
+    @Override
+    public DOMStoreReadTransaction newReadOnlyTransaction() {
+        return new TransactionProxy();
+    }
+
+    @Override
+    public DOMStoreWriteTransaction newWriteOnlyTransaction() {
+        return new TransactionProxy();
+    }
+
+    @Override
+    public DOMStoreReadWriteTransaction newReadWriteTransaction() {
+        return new TransactionProxy();
+    }
+}
diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ListenerRegistrationProxy.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ListenerRegistrationProxy.java
new file mode 100644 (file)
index 0000000..19e7f19
--- /dev/null
@@ -0,0 +1,21 @@
+package org.opendaylight.controller.cluster.datastore;
+
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+
+/**
+ * ListenerRegistrationProxy acts as a proxy for a ListenerRegistration that was done on a remote shard
+ *
+ * Registering a DataChangeListener on the Data Store creates a new instance of the ListenerRegistrationProxy
+ * The ListenerRegistrationProxy talks to a remote ListenerRegistration actor.
+ */
+public class ListenerRegistrationProxy implements ListenerRegistration {
+    @Override
+    public Object getInstance() {
+        throw new UnsupportedOperationException("getInstance");
+    }
+
+    @Override
+    public void close() {
+        throw new UnsupportedOperationException("close");
+    }
+}
diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/TransactionChainProxy.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/TransactionChainProxy.java
new file mode 100644 (file)
index 0000000..20a74e3
--- /dev/null
@@ -0,0 +1,31 @@
+package org.opendaylight.controller.cluster.datastore;
+
+import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadTransaction;
+import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadWriteTransaction;
+import org.opendaylight.controller.sal.core.spi.data.DOMStoreTransactionChain;
+import org.opendaylight.controller.sal.core.spi.data.DOMStoreWriteTransaction;
+
+/**
+ * TransactionChainProxy acts as a proxy for a DOMStoreTransactionChain created on a remote shard
+ */
+public class TransactionChainProxy implements DOMStoreTransactionChain{
+    @Override
+    public DOMStoreReadTransaction newReadOnlyTransaction() {
+        throw new UnsupportedOperationException("newReadOnlyTransaction");
+    }
+
+    @Override
+    public DOMStoreReadWriteTransaction newReadWriteTransaction() {
+        throw new UnsupportedOperationException("newReadWriteTransaction");
+    }
+
+    @Override
+    public DOMStoreWriteTransaction newWriteOnlyTransaction() {
+        throw new UnsupportedOperationException("newWriteOnlyTransaction");
+    }
+
+    @Override
+    public void close() {
+        throw new UnsupportedOperationException("close");
+    }
+}
diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/TransactionProxy.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/TransactionProxy.java
new file mode 100644 (file)
index 0000000..c9a6304
--- /dev/null
@@ -0,0 +1,56 @@
+package org.opendaylight.controller.cluster.datastore;
+
+import com.google.common.base.Optional;
+import com.google.common.util.concurrent.ListenableFuture;
+import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadWriteTransaction;
+import org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCohort;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+/**
+ * TransactionProxy acts as a proxy for one or more transactions that were created on a remote shard
+ *
+ * Creating a transaction on the consumer side will create one instance of a transaction proxy. If during
+ * the transaction reads and writes are done on data that belongs to different shards then a separate transaction will
+ * be created on each of those shards by the TransactionProxy
+ *
+ * The TransactionProxy does not make any guarantees about atomicity or order in which the transactions on the various
+ * shards will be executed.
+ *
+ */
+public class TransactionProxy implements DOMStoreReadWriteTransaction {
+    @Override
+    public ListenableFuture<Optional<NormalizedNode<?, ?>>> read(InstanceIdentifier path) {
+        throw new UnsupportedOperationException("read");
+    }
+
+    @Override
+    public void write(InstanceIdentifier path, NormalizedNode<?, ?> data) {
+        throw new UnsupportedOperationException("write");
+    }
+
+    @Override
+    public void merge(InstanceIdentifier path, NormalizedNode<?, ?> data) {
+        throw new UnsupportedOperationException("merge");
+    }
+
+    @Override
+    public void delete(InstanceIdentifier path) {
+        throw new UnsupportedOperationException("delete");
+    }
+
+    @Override
+    public DOMStoreThreePhaseCommitCohort ready() {
+        throw new UnsupportedOperationException("ready");
+    }
+
+    @Override
+    public Object getIdentifier() {
+        throw new UnsupportedOperationException("getIdentifier");
+    }
+
+    @Override
+    public void close() {
+        throw new UnsupportedOperationException("close");
+    }
+}
diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/config/yang/config/distributed_datastore_provider/DistributedDataStoreProviderModule.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/config/yang/config/distributed_datastore_provider/DistributedDataStoreProviderModule.java
new file mode 100644 (file)
index 0000000..241bcb0
--- /dev/null
@@ -0,0 +1,34 @@
+package org.opendaylight.controller.config.yang.config.distributed_datastore_provider;
+
+import org.opendaylight.controller.cluster.datastore.DistributedDataStore;
+
+public class DistributedDataStoreProviderModule extends org.opendaylight.controller.config.yang.config.distributed_datastore_provider.AbstractDistributedDataStoreProviderModule {
+    public DistributedDataStoreProviderModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
+        super(identifier, dependencyResolver);
+    }
+
+    public DistributedDataStoreProviderModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, org.opendaylight.controller.config.yang.config.distributed_datastore_provider.DistributedDataStoreProviderModule oldModule, java.lang.AutoCloseable oldInstance) {
+        super(identifier, dependencyResolver, oldModule, oldInstance);
+    }
+
+    @Override
+    public void customValidation() {
+        // add custom validation form module attributes here.
+    }
+
+    @Override
+    public java.lang.AutoCloseable createInstance() {
+        new DistributedDataStore();
+
+        final class AutoCloseableDistributedDataStore implements AutoCloseable {
+
+            @Override
+            public void close() throws Exception {
+
+            }
+        }
+
+        return new AutoCloseableDistributedDataStore();
+    }
+
+}
diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/config/yang/config/distributed_datastore_provider/DistributedDataStoreProviderModuleFactory.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/config/yang/config/distributed_datastore_provider/DistributedDataStoreProviderModuleFactory.java
new file mode 100644 (file)
index 0000000..53ef84e
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+* Generated file
+*
+* Generated from: yang module name: distributed-datastore-provider yang module local name: distributed-datastore-provider
+* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
+* Generated at: Thu Jun 12 15:23:43 PDT 2014
+*
+* Do not modify this file unless it is present under src/main directory
+*/
+package org.opendaylight.controller.config.yang.config.distributed_datastore_provider;
+public class DistributedDataStoreProviderModuleFactory extends org.opendaylight.controller.config.yang.config.distributed_datastore_provider.AbstractDistributedDataStoreProviderModuleFactory {
+
+}
diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/yang/distributed-datastore-provider.yang b/opendaylight/md-sal/sal-distributed-datastore/src/main/yang/distributed-datastore-provider.yang
new file mode 100644 (file)
index 0000000..0471bc8
--- /dev/null
@@ -0,0 +1,34 @@
+// vi: set smarttab et sw=4 tabstop=4:
+module distributed-datastore-provider {
+
+    yang-version 1;
+    namespace "urn:opendaylight:params:xml:ns:yang:controller:config:distributed-datastore-provider";
+    prefix "distributed-datastore-provider";
+
+    import config { prefix config; revision-date 2013-04-05; }
+    import rpc-context { prefix rpcx; revision-date 2013-06-17; }
+
+    description
+        "This module contains the base YANG definitions for
+        the distributed datastore provider implementation";
+
+    revision "2014-06-12" {
+        description
+            "Initial revision.";
+    }
+
+    // This is the definition of the service implementation as a module identity.
+    identity distributed-datastore-provider {
+            base config:module-type;
+
+            // Specifies the prefix for generated java classes.
+            config:java-name-prefix DistributedDataStoreProvider;
+    }
+
+    // Augments the 'configuration' choice node under modules/module.
+    augment "/config:modules/config:module/config:configuration" {
+        case distributed-datastore-provider {
+            when "/config:modules/config:module/config:type = 'distributed-datastore-provider'";
+        }
+    }
+}
diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/DistributedDataStoreTest.java b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/DistributedDataStoreTest.java
new file mode 100644 (file)
index 0000000..6544f33
--- /dev/null
@@ -0,0 +1,65 @@
+package org.opendaylight.controller.cluster.datastore;
+
+import junit.framework.Assert;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeListener;
+import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadTransaction;
+import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadWriteTransaction;
+import org.opendaylight.controller.sal.core.spi.data.DOMStoreTransactionChain;
+import org.opendaylight.controller.sal.core.spi.data.DOMStoreWriteTransaction;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+public class DistributedDataStoreTest {
+
+    private DistributedDataStore distributedDataStore;
+
+    @org.junit.Before
+    public void setUp() throws Exception {
+        distributedDataStore = new DistributedDataStore();
+    }
+
+    @org.junit.After
+    public void tearDown() throws Exception {
+
+    }
+
+    @org.junit.Test
+    public void testRegisterChangeListener() throws Exception {
+        ListenerRegistration registration =
+                distributedDataStore.registerChangeListener(InstanceIdentifier.builder().build(), new AsyncDataChangeListener<InstanceIdentifier, NormalizedNode<?, ?>>() {
+            @Override
+            public void onDataChanged(AsyncDataChangeEvent<InstanceIdentifier, NormalizedNode<?, ?>> change) {
+                throw new UnsupportedOperationException("onDataChanged");
+            }
+        }, AsyncDataBroker.DataChangeScope.BASE);
+
+        Assert.assertNotNull(registration);
+    }
+
+    @org.junit.Test
+    public void testCreateTransactionChain() throws Exception {
+        final DOMStoreTransactionChain transactionChain = distributedDataStore.createTransactionChain();
+        Assert.assertNotNull(transactionChain);
+    }
+
+    @org.junit.Test
+    public void testNewReadOnlyTransaction() throws Exception {
+        final DOMStoreReadTransaction transaction = distributedDataStore.newReadOnlyTransaction();
+        Assert.assertNotNull(transaction);
+    }
+
+    @org.junit.Test
+    public void testNewWriteOnlyTransaction() throws Exception {
+        final DOMStoreWriteTransaction transaction = distributedDataStore.newWriteOnlyTransaction();
+        Assert.assertNotNull(transaction);
+    }
+
+    @org.junit.Test
+    public void testNewReadWriteTransaction() throws Exception {
+        final DOMStoreReadWriteTransaction transaction = distributedDataStore.newReadWriteTransaction();
+        Assert.assertNotNull(transaction);
+    }
+}
index dbaba294aa1872b2261a0502da6a450dc7e4af9b..c120508f875acfc0f5710aaced9d699204307fbc 100644 (file)
@@ -1,6 +1,5 @@
 /*
- * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
- *
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
  * and is available at http://www.eclipse.org/legal/epl-v10.html
@@ -8,17 +7,45 @@
 package org.opendaylight.controller.md.sal.dom.api;
 
 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionChainFactory;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
 import org.opendaylight.controller.sal.core.api.BrokerService;
 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
 
-public interface DOMDataBroker extends AsyncDataBroker<InstanceIdentifier, NormalizedNode<?, ?>, DOMDataChangeListener>, BrokerService {
+/**
+ * Data Broker which provides data transaction and data change listener fuctionality
+ * using {@link NormalizedNode} data format.
+ *
+ * This interface is type capture of generic interfaces and returns type captures
+ * of results for client-code convenience.
+ *
+ */
+public interface DOMDataBroker extends
+        AsyncDataBroker<InstanceIdentifier, NormalizedNode<?, ?>, DOMDataChangeListener>,
+        TransactionChainFactory<InstanceIdentifier, NormalizedNode<?, ?>>, BrokerService {
+
+    /**
+     * {@inheritDoc}
+     */
     @Override
     DOMDataReadTransaction newReadOnlyTransaction();
 
+    /**
+     * {@inheritDoc}
+     */
     @Override
     DOMDataReadWriteTransaction newReadWriteTransaction();
 
+    /**
+     * {@inheritDoc}
+     */
     @Override
     DOMDataWriteTransaction newWriteOnlyTransaction();
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    DOMTransactionChain createTransactionChain(TransactionChainListener listener);
 }
diff --git a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMTransactionChain.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMTransactionChain.java
new file mode 100644 (file)
index 0000000..b894911
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.sal.dom.api;
+
+import org.opendaylight.controller.md.sal.common.api.data.TransactionChain;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+/**
+ * A chain of DOM Data transactions.
+ *
+ * Transactions in a chain need to be committed in sequence and each
+ * transaction should see the effects of previous transactions as if they happened. A chain
+ * makes no guarantees of atomicity, in fact transactions are committed as soon as possible.
+ *
+ * <p>
+ * This interface is type capture of {@link TransactionChain} for DOM Data Contracts.
+ */
+public interface DOMTransactionChain extends TransactionChain<InstanceIdentifier, NormalizedNode<?, ?>> {
+
+    @Override
+    DOMDataReadTransaction newReadOnlyTransaction();
+
+    @Override
+    DOMDataReadWriteTransaction newReadWriteTransaction();
+
+    @Override
+    DOMDataWriteTransaction newWriteOnlyTransaction();
+
+}
diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/AbstractDOMForwardedCompositeTransaction.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/AbstractDOMForwardedCompositeTransaction.java
new file mode 100644 (file)
index 0000000..0c07b06
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.sal.dom.broker.impl;
+
+import org.opendaylight.controller.md.sal.common.api.data.AsyncTransaction;
+import org.opendaylight.controller.sal.core.spi.data.DOMStoreTransaction;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableMap;
+
+/**
+ * Composite DOM Transaction backed by {@link DOMStoreTransaction}.
+ *
+ * Abstract base for composite transaction, which provides access only to common
+ * functionality as retrieval of subtransaction, close method and retrieval of
+ * identifier.
+ *
+ * @param <K>
+ *            Subtransaction distinguisher
+ * @param <T>
+ *            Subtransaction type
+ */
+abstract class AbstractDOMForwardedCompositeTransaction<K, T extends DOMStoreTransaction> implements
+        AsyncTransaction<InstanceIdentifier, NormalizedNode<?, ?>> {
+
+    private final ImmutableMap<K, T> backingTxs;
+    private final Object identifier;
+
+    /**
+     *
+     * Creates new composite Transactions.
+     *
+     * @param identifier
+     *            Identifier of transaction.
+     * @param backingTxs
+     *            Key,value map of backing transactions.
+     */
+    protected AbstractDOMForwardedCompositeTransaction(final Object identifier, final ImmutableMap<K, T> backingTxs) {
+        this.identifier = Preconditions.checkNotNull(identifier, "Identifier should not be null");
+        this.backingTxs = Preconditions.checkNotNull(backingTxs, "Backing transactions should not be null");
+    }
+
+    /**
+     * Returns subtransaction associated with supplied key.
+     *
+     * @param key
+     * @return
+     * @throws NullPointerException
+     *             if key is null
+     * @throws IllegalArgumentException
+     *             if no subtransaction is associated with key.
+     */
+    protected final T getSubtransaction(final K key) {
+        Preconditions.checkNotNull(key, "key must not be null.");
+        Preconditions.checkArgument(backingTxs.containsKey(key), "No subtransaction associated with %s", key);
+        return backingTxs.get(key);
+    }
+
+    /**
+     * Returns immutable Iterable of all subtransactions.
+     *
+     */
+    protected Iterable<T> getSubtransactions() {
+        return backingTxs.values();
+    }
+
+    @Override
+    public Object getIdentifier() {
+        return identifier;
+    }
+
+    @Override
+    public void close() {
+        /*
+         *  We share one exception for all failures, which are added
+         *  as supressedExceptions to it.
+         *
+         */
+        IllegalStateException failure = null;
+        for (T subtransaction : backingTxs.values()) {
+            try {
+                subtransaction.close();
+            } catch (Exception e) {
+                // If we did not allocated failure we allocate it
+                if(failure == null) {
+                    failure = new IllegalStateException("Uncaught exception occured during closing transaction.", e);
+                } else {
+                    // We update it with addotional exceptions, which occured during error.
+                    failure.addSuppressed(e);
+                }
+            }
+        }
+        // If we have failure, we throw it at after all attempts to close.
+        if(failure != null) {
+            throw failure;
+        }
+    }
+}
\ No newline at end of file
diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/AbstractDOMForwardedTransactionFactory.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/AbstractDOMForwardedTransactionFactory.java
new file mode 100644 (file)
index 0000000..2203087
--- /dev/null
@@ -0,0 +1,223 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.sal.dom.broker.impl;
+
+import java.util.Map;
+import java.util.Map.Entry;
+
+import javax.annotation.concurrent.GuardedBy;
+
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataReadTransaction;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
+import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadTransaction;
+import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadWriteTransaction;
+import org.opendaylight.controller.sal.core.spi.data.DOMStoreTransactionFactory;
+import org.opendaylight.controller.sal.core.spi.data.DOMStoreWriteTransaction;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableMap;
+
+/**
+ *
+ * Abstract composite transaction factory.
+ *
+ * Provides an convenience common implementation for composite DOM Transactions,
+ * where subtransaction is identified by {@link LogicalDatastoreType} type and
+ * implementation of subtransaction is provided by
+ * {@link DOMStoreTransactionFactory}.
+ *
+ * <b>Note:</b>This class does not have thread-safe implementation of  {@link #close()},
+ *   implementation may allow accessing and allocating new transactions during closing
+ *   this instance.
+ *
+ * @param <T>
+ *            Type of {@link DOMStoreTransactionFactory} factory.
+ */
+public abstract class AbstractDOMForwardedTransactionFactory<T extends DOMStoreTransactionFactory> implements DOMDataCommitImplementation, AutoCloseable {
+
+    private final ImmutableMap<LogicalDatastoreType, T> storeTxFactories;
+
+    private boolean closed;
+
+    protected AbstractDOMForwardedTransactionFactory(final Map<LogicalDatastoreType, ? extends T> txFactories) {
+        this.storeTxFactories = ImmutableMap.copyOf(txFactories);
+    }
+
+    /**
+     * Implementations must return unique identifier for each and every call of
+     * this method;
+     *
+     * @return new Unique transaction identifier.
+     */
+    protected abstract Object newTransactionIdentifier();
+
+    /**
+     * Creates a new composite read-only transaction
+     *
+     * Creates a new composite read-only transaction backed by one transaction
+     * per factory in {@link #getTxFactories()}.
+     *
+     * Subtransaction for reading is selected by supplied
+     * {@link LogicalDatastoreType} as parameter for
+     * {@link DOMDataReadTransaction#read(LogicalDatastoreType,org.opendaylight.yangtools.yang.data.api.InstanceIdentifier)}
+     * .
+     *
+     * Id of returned transaction is retrieved via
+     * {@link #newTransactionIdentifier()}.
+     *
+     * @return New composite read-only transaction.
+     */
+    public DOMDataReadTransaction newReadOnlyTransaction() {
+        checkNotClosed();
+        ImmutableMap.Builder<LogicalDatastoreType, DOMStoreReadTransaction> builder = ImmutableMap.builder();
+        for (Entry<LogicalDatastoreType, T> store : storeTxFactories.entrySet()) {
+            builder.put(store.getKey(), store.getValue().newReadOnlyTransaction());
+        }
+        return new DOMForwardedReadOnlyTransaction(newTransactionIdentifier(), builder.build());
+    }
+
+
+
+    /**
+     * Creates a new composite write-only transaction
+     *
+     * <p>
+     * Creates a new composite write-only transaction backed by one write-only
+     * transaction per factory in {@link #getTxFactories()}.
+     *
+     * <p>
+     * Implementation of composite Write-only transaction is following:
+     *
+     * <ul>
+     * <li>
+     * {@link DOMDataWriteTransaction#put(LogicalDatastoreType, org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode)}
+     * - backing subtransaction is selected by {@link LogicalDatastoreType},
+     * {@link DOMStoreWriteTransaction#write(org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode)}
+     * is invoked on selected subtransaction.
+     * <li>
+     * {@link DOMDataWriteTransaction#merge(LogicalDatastoreType, org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode)}
+     * - backing subtransaction is selected by {@link LogicalDatastoreType},
+     * {@link DOMStoreWriteTransaction#merge(org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode)}
+     * is invoked on selected subtransaction.
+     * <li>
+     * {@link DOMDataWriteTransaction#delete(LogicalDatastoreType, org.opendaylight.yangtools.yang.data.api.InstanceIdentifier)
+     * - backing subtransaction is selected by {@link LogicalDatastoreType},
+     * {@link DOMStoreWriteTransaction#delete(org.opendaylight.yangtools.yang.data.api.InstanceIdentifier)} is invoked on
+     * selected subtransaction.
+     * <li> {@link DOMDataWriteTransaction#commit()} - results in invoking
+     * {@link DOMStoreWriteTransaction#ready()}, gathering all resulting cohorts
+     * and then invoking finalized implementation callback
+     * {@link #commit(DOMDataWriteTransaction, Iterable)} with transaction which
+     * was commited and gathered results.
+     * </ul>
+     *
+     * Id of returned transaction is generated via
+     * {@link #newTransactionIdentifier()}.
+     *
+     * @return New composite write-only transaction associated with this
+     *         factory.
+     */
+    public DOMDataWriteTransaction newWriteOnlyTransaction() {
+        checkNotClosed();
+        ImmutableMap.Builder<LogicalDatastoreType, DOMStoreWriteTransaction> builder = ImmutableMap.builder();
+        for (Entry<LogicalDatastoreType, T> store : storeTxFactories.entrySet()) {
+            builder.put(store.getKey(), store.getValue().newWriteOnlyTransaction());
+        }
+        return new DOMForwardedWriteTransaction<DOMStoreWriteTransaction>(newTransactionIdentifier(), builder.build(),
+                this);
+    }
+
+    /**
+     * Creates a new composite write-only transaction
+     *
+     * <p>
+     * Creates a new composite write-only transaction backed by one write-only
+     * transaction per factory in {@link #getTxFactories()}.
+     * <p>
+     * Implementation of composite Write-only transaction is following:
+     *
+     * <ul>
+     * <li>
+     * {@link DOMDataWriteTransaction#read(LogicalDatastoreType, org.opendaylight.yangtools.yang.data.api.InstanceIdentifier)}
+     * - backing subtransaction is selected by {@link LogicalDatastoreType},
+     * {@link DOMStoreWriteTransaction#read(org.opendaylight.yangtools.yang.data.api.InstanceIdentifier)} is invoked on
+     * selected subtransaction.
+     * <li>
+     * {@link DOMDataWriteTransaction#put(LogicalDatastoreType, org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode)}
+     * - backing subtransaction is selected by {@link LogicalDatastoreType},
+     * {@link DOMStoreWriteTransaction#write(org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode)}
+     * is invoked on selected subtransaction.
+     * <li>
+     * {@link DOMDataWriteTransaction#merge(LogicalDatastoreType, org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode)}
+     * - backing subtransaction is selected by {@link LogicalDatastoreType},
+     * {@link DOMStoreWriteTransaction#merge(org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode)}
+     * is invoked on selected subtransaction.
+     * <li>
+     * {@link DOMDataWriteTransaction#delete(LogicalDatastoreType, org.opendaylight.yangtools.yang.data.api.InstanceIdentifier)
+     * - backing subtransaction is selected by {@link LogicalDatastoreType},
+     * {@link DOMStoreWriteTransaction#delete(org.opendaylight.yangtools.yang.data.api.InstanceIdentifier)} is invoked on
+     * selected subtransaction.
+     * <li> {@link DOMDataWriteTransaction#commit()} - results in invoking
+     * {@link DOMStoreWriteTransaction#ready()}, gathering all resulting cohorts
+     * and then invoking finalized implementation callback
+     * {@link #commit(DOMDataWriteTransaction, Iterable)} with transaction which
+     * was commited and gathered results.
+     * <li>
+     * </ul>
+     *
+     * Id of returned transaction is generated via
+     * {@link #newTransactionIdentifier()}.
+     *
+     * @return New composite read-write transaction associated with this
+     *         factory.
+     *
+     */
+    public DOMDataReadWriteTransaction newReadWriteTransaction() {
+        checkNotClosed();
+        ImmutableMap.Builder<LogicalDatastoreType, DOMStoreReadWriteTransaction> builder = ImmutableMap.builder();
+        for (Entry<LogicalDatastoreType, T> store : storeTxFactories.entrySet()) {
+            builder.put(store.getKey(), store.getValue().newReadWriteTransaction());
+        }
+        return new DOMForwardedReadWriteTransaction(newTransactionIdentifier(), builder.build(), this);
+    }
+
+    /**
+     * Convenience accessor of backing factories intended to be used only by
+     * finalization of this class.
+     *
+     * <b>Note:</b>
+     * Finalization of this class may want to access other functionality of
+     * supplied Transaction factories.
+     *
+     * @return Map of backing transaction factories.
+     */
+    protected final Map<LogicalDatastoreType, T> getTxFactories() {
+        return storeTxFactories;
+    }
+
+    /**
+     *
+     * Checks if instance is not closed.
+     *
+     * @throws IllegalStateException If instance of this class was closed.
+     *
+     */
+    @GuardedBy("this")
+    protected synchronized void checkNotClosed() {
+        Preconditions.checkState(!closed,"Transaction factory was closed. No further operations allowed.");
+    }
+
+    @Override
+    @GuardedBy("this")
+    public synchronized void close() {
+        closed = true;
+    }
+
+}
index 608ac9bc68d120c39d96b0389bbed324ba01652e..7e37a1e3a3467837b16963a8026236738535f599 100644 (file)
  */
 package org.opendaylight.controller.md.sal.dom.broker.impl;
 
-import static com.google.common.base.Preconditions.checkNotNull;
 import static com.google.common.base.Preconditions.checkState;
 
-import java.util.Collections;
-import java.util.List;
 import java.util.Map.Entry;
-import java.util.concurrent.Callable;
-import java.util.concurrent.ExecutionException;
 import java.util.concurrent.atomic.AtomicLong;
 
 import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
-import org.opendaylight.controller.md.sal.common.api.data.AsyncTransaction;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
 import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
 import org.opendaylight.controller.md.sal.dom.api.DOMDataChangeListener;
-import org.opendaylight.controller.md.sal.dom.api.DOMDataReadTransaction;
-import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction;
 import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
-import org.opendaylight.controller.sal.common.util.Rpcs;
+import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain;
 import org.opendaylight.controller.sal.core.spi.data.DOMStore;
-import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadTransaction;
-import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadWriteTransaction;
 import org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCohort;
-import org.opendaylight.controller.sal.core.spi.data.DOMStoreTransaction;
-import org.opendaylight.controller.sal.core.spi.data.DOMStoreWriteTransaction;
+import org.opendaylight.controller.sal.core.spi.data.DOMStoreTransactionChain;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
-import org.opendaylight.yangtools.yang.common.RpcError;
 import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
-import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.google.common.base.Function;
 import com.google.common.base.Optional;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableList.Builder;
 import com.google.common.collect.ImmutableMap;
-import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.ListenableFuture;
 import com.google.common.util.concurrent.ListeningExecutorService;
 
-public class DOMDataBrokerImpl implements DOMDataBroker, AutoCloseable {
+public class DOMDataBrokerImpl extends AbstractDOMForwardedTransactionFactory<DOMStore> implements DOMDataBroker,
+        AutoCloseable {
 
     private static final Logger LOG = LoggerFactory.getLogger(DOMDataBrokerImpl.class);
-    private static final Logger COORDINATOR_LOG = LoggerFactory.getLogger(CommitCoordination.class);
-    private final ImmutableMap<LogicalDatastoreType, DOMStore> datastores;
-    private final ListeningExecutorService executor;
+
+    private final DOMDataCommitCoordinatorImpl coordinator;
     private final AtomicLong txNum = new AtomicLong();
+    private final AtomicLong chainNum = new AtomicLong();
 
     public DOMDataBrokerImpl(final ImmutableMap<LogicalDatastoreType, DOMStore> datastores,
             final ListeningExecutorService executor) {
-        super();
-        this.datastores = datastores;
-        this.executor = executor;
+        super(datastores);
+        this.coordinator = new DOMDataCommitCoordinatorImpl(executor);
     }
 
-    private static final Function<Iterable<Boolean>, Boolean> AND_FUNCTION = new Function<Iterable<Boolean>, Boolean>() {
-
-        @Override
-        public Boolean apply(final Iterable<Boolean> input) {
-
-            for (Boolean value : input) {
-                if (value == false) {
-                    return Boolean.FALSE;
-                }
-            }
-            return Boolean.TRUE;
-        }
-    };
-
     @Override
-    public DOMDataReadTransaction newReadOnlyTransaction() {
-        ImmutableMap.Builder<LogicalDatastoreType, DOMStoreReadTransaction> builder = ImmutableMap.builder();
-        for (Entry<LogicalDatastoreType, DOMStore> store : datastores.entrySet()) {
-            builder.put(store.getKey(), store.getValue().newReadOnlyTransaction());
-        }
-        return new ReadOnlyTransactionImpl(newTransactionIdentifier(), builder.build());
-    }
-
-    private Object newTransactionIdentifier() {
+    protected Object newTransactionIdentifier() {
         return "DOM-" + txNum.getAndIncrement();
     }
 
-    @Override
-    public DOMDataReadWriteTransaction newReadWriteTransaction() {
-        ImmutableMap.Builder<LogicalDatastoreType, DOMStoreReadWriteTransaction> builder = ImmutableMap.builder();
-        for (Entry<LogicalDatastoreType, DOMStore> store : datastores.entrySet()) {
-            builder.put(store.getKey(), store.getValue().newReadWriteTransaction());
-        }
-        return new ReadWriteTransactionImpl(newTransactionIdentifier(), builder.build(), this);
-    }
-
-    @Override
-    public DOMDataWriteTransaction newWriteOnlyTransaction() {
-        ImmutableMap.Builder<LogicalDatastoreType, DOMStoreWriteTransaction> builder = ImmutableMap.builder();
-        for (Entry<LogicalDatastoreType, DOMStore> store : datastores.entrySet()) {
-            builder.put(store.getKey(), store.getValue().newWriteOnlyTransaction());
-        }
-        return new WriteTransactionImpl<DOMStoreWriteTransaction>(newTransactionIdentifier(), builder.build(), this);
-    }
-
     @Override
     public ListenerRegistration<DOMDataChangeListener> registerDataChangeListener(final LogicalDatastoreType store,
             final InstanceIdentifier path, final DOMDataChangeListener listener, final DataChangeScope triggeringScope) {
 
-        DOMStore potentialStore = datastores.get(store);
+        DOMStore potentialStore = getTxFactories().get(store);
         checkState(potentialStore != null, "Requested logical data store is not available.");
         return potentialStore.registerChangeListener(path, listener, triggeringScope);
     }
 
-    private ListenableFuture<RpcResult<TransactionStatus>> submit(
-            final WriteTransactionImpl<? extends DOMStoreWriteTransaction> transaction) {
-        LOG.debug("Tx: {} is submitted for execution.", transaction.getIdentifier());
-        return executor.submit(new CommitCoordination(transaction));
-    }
-
-    private abstract static class AbstractCompositeTransaction<K, T extends DOMStoreTransaction> implements
-            AsyncTransaction<InstanceIdentifier, NormalizedNode<?, ?>> {
-
-        private final ImmutableMap<K, T> backingTxs;
-        private final Object identifier;
-
-        protected AbstractCompositeTransaction(final Object identifier, final ImmutableMap<K, T> backingTxs) {
-            this.identifier = checkNotNull(identifier, "Identifier should not be null");
-            this.backingTxs = checkNotNull(backingTxs, "Backing transactions should not be null");
-        }
-
-        protected T getSubtransaction(final K key) {
-            return backingTxs.get(key);
-        }
-
-        public Iterable<T> getSubtransactions() {
-            return backingTxs.values();
-        }
-
-        @Override
-        public Object getIdentifier() {
-            return identifier;
-        }
-
-        @Override
-        public void close() {
-            try {
-                for (T subtransaction : backingTxs.values()) {
-                    subtransaction.close();
-                }
-            } catch (Exception e) {
-                throw new IllegalStateException("Uncaught exception occured during closing transaction.", e);
-            }
-        }
-
-    }
-
-    private static class ReadOnlyTransactionImpl extends
-            AbstractCompositeTransaction<LogicalDatastoreType, DOMStoreReadTransaction> implements
-            DOMDataReadTransaction {
-
-        protected ReadOnlyTransactionImpl(final Object identifier,
-                final ImmutableMap<LogicalDatastoreType, DOMStoreReadTransaction> backingTxs) {
-            super(identifier, backingTxs);
-        }
-
-        @Override
-        public ListenableFuture<Optional<NormalizedNode<?, ?>>> read(final LogicalDatastoreType store,
-                final InstanceIdentifier path) {
-            return getSubtransaction(store).read(path);
-        }
-
-    }
-
-    private static class WriteTransactionImpl<T extends DOMStoreWriteTransaction> extends
-            AbstractCompositeTransaction<LogicalDatastoreType, T> implements DOMDataWriteTransaction {
-
-        private final DOMDataBrokerImpl broker;
-        private ImmutableList<DOMStoreThreePhaseCommitCohort> cohorts;
-
-        protected WriteTransactionImpl(final Object identifier, final ImmutableMap<LogicalDatastoreType, T> backingTxs,
-                final DOMDataBrokerImpl broker) {
-            super(identifier, backingTxs);
-            this.broker = broker;
-        }
-
-        public synchronized Iterable<DOMStoreThreePhaseCommitCohort> ready() {
-            checkState(cohorts == null, "Transaction was already marked as ready.");
-            ImmutableList.Builder<DOMStoreThreePhaseCommitCohort> cohortsBuilder = ImmutableList.builder();
-            for (DOMStoreWriteTransaction subTx : getSubtransactions()) {
-                cohortsBuilder.add(subTx.ready());
-            }
-            cohorts = cohortsBuilder.build();
-            return cohorts;
-        }
-
-        protected ImmutableList<DOMStoreThreePhaseCommitCohort> getCohorts() {
-            return cohorts;
-        }
-
-        @Override
-        public void put(final LogicalDatastoreType store, final InstanceIdentifier path, final NormalizedNode<?, ?> data) {
-            getSubtransaction(store).write(path, data);
-        }
-
-        @Override
-        public void delete(final LogicalDatastoreType store, final InstanceIdentifier path) {
-            getSubtransaction(store).delete(path);
-        }
-
-        @Override
-        public void merge(final LogicalDatastoreType store, final InstanceIdentifier path,
-                final NormalizedNode<?, ?> data) {
-            getSubtransaction(store).merge(path,data);
-        }
-
-        @Override
-        public void cancel() {
-            // TODO Auto-generated method stub
-
-        }
-
-        @Override
-        public ListenableFuture<RpcResult<TransactionStatus>> commit() {
-
-            ready();
-            return broker.submit(this);
-        }
-
-    }
-
-    private static class ReadWriteTransactionImpl extends WriteTransactionImpl<DOMStoreReadWriteTransaction> implements
-            DOMDataReadWriteTransaction {
-
-        protected ReadWriteTransactionImpl(final Object identifier,
-                final ImmutableMap<LogicalDatastoreType, DOMStoreReadWriteTransaction> backingTxs,
-                final DOMDataBrokerImpl broker) {
-            // super(identifier, backingTxs);
-            super(identifier, backingTxs, broker);
-        }
-
-        @Override
-        public ListenableFuture<Optional<NormalizedNode<?, ?>>> read(final LogicalDatastoreType store,
-                final InstanceIdentifier path) {
-            return getSubtransaction(store).read(path);
-        }
-    }
-
-    private final class CommitCoordination implements Callable<RpcResult<TransactionStatus>> {
-
-        private final WriteTransactionImpl<? extends DOMStoreWriteTransaction> transaction;
-
-        public CommitCoordination(final WriteTransactionImpl<? extends DOMStoreWriteTransaction> transaction) {
-            this.transaction = transaction;
-        }
-
-        @Override
-        public RpcResult<TransactionStatus> call() throws Exception {
-
-            try {
-                Boolean canCommit = canCommit().get();
-
-                if (canCommit) {
-                    try {
-                        preCommit().get();
-                        try {
-                            commit().get();
-                            COORDINATOR_LOG.debug("Tx: {} Is commited.", transaction.getIdentifier());
-                            return Rpcs.getRpcResult(true, TransactionStatus.COMMITED,
-                                    Collections.<RpcError> emptySet());
-
-                        } catch (InterruptedException | ExecutionException e) {
-                            COORDINATOR_LOG.error("Tx: {} Error during commit", transaction.getIdentifier(), e);
-                        }
-
-                    } catch (InterruptedException | ExecutionException e) {
-                        COORDINATOR_LOG.warn("Tx: {} Error during preCommit, starting Abort",
-                                transaction.getIdentifier(), e);
-                    }
-                } else {
-                    COORDINATOR_LOG.info("Tx: {} Did not pass canCommit phase.", transaction.getIdentifier());
-                    abort().get();
-                }
-            } catch (InterruptedException | ExecutionException e) {
-                COORDINATOR_LOG.warn("Tx: {} Error during canCommit, starting Abort", transaction.getIdentifier(), e);
-
-            }
-            try {
-                abort().get();
-            } catch (InterruptedException | ExecutionException e) {
-                COORDINATOR_LOG.error("Tx: {} Error during abort", transaction.getIdentifier(), e);
-            }
-            return Rpcs.getRpcResult(false, TransactionStatus.FAILED, Collections.<RpcError> emptySet());
-        }
-
-        public ListenableFuture<Void> preCommit() {
-            COORDINATOR_LOG.debug("Transaction {}: PreCommit Started ", transaction.getIdentifier());
-            Builder<ListenableFuture<Void>> ops = ImmutableList.builder();
-            for (DOMStoreThreePhaseCommitCohort cohort : transaction.getCohorts()) {
-                ops.add(cohort.preCommit());
-            }
-            return (ListenableFuture) Futures.allAsList(ops.build());
-        }
-
-        public ListenableFuture<Void> commit() {
-            COORDINATOR_LOG.debug("Transaction {}: Commit Started ", transaction.getIdentifier());
-            Builder<ListenableFuture<Void>> ops = ImmutableList.builder();
-            for (DOMStoreThreePhaseCommitCohort cohort : transaction.getCohorts()) {
-                ops.add(cohort.commit());
-            }
-            return (ListenableFuture) Futures.allAsList(ops.build());
-        }
-
-        public ListenableFuture<Boolean> canCommit() {
-            COORDINATOR_LOG.debug("Transaction {}: CanCommit Started ", transaction.getIdentifier());
-            Builder<ListenableFuture<Boolean>> canCommitOperations = ImmutableList.builder();
-            for (DOMStoreThreePhaseCommitCohort cohort : transaction.getCohorts()) {
-                canCommitOperations.add(cohort.canCommit());
-            }
-            ListenableFuture<List<Boolean>> allCanCommits = Futures.allAsList(canCommitOperations.build());
-            return Futures.transform(allCanCommits, AND_FUNCTION);
-        }
-
-        public ListenableFuture<Void> abort() {
-            COORDINATOR_LOG.debug("Transaction {}: Abort Started ", transaction.getIdentifier());
-            Builder<ListenableFuture<Void>> ops = ImmutableList.builder();
-            for (DOMStoreThreePhaseCommitCohort cohort : transaction.getCohorts()) {
-                ops.add(cohort.abort());
-            }
-            return (ListenableFuture) Futures.allAsList(ops.build());
-        };
+    @Override
+    public DOMTransactionChain createTransactionChain(final TransactionChainListener listener) {
+        ImmutableMap.Builder<LogicalDatastoreType, DOMStoreTransactionChain> backingChainsBuilder = ImmutableMap
+                .builder();
+        for (Entry<LogicalDatastoreType, DOMStore> entry : getTxFactories().entrySet()) {
+            backingChainsBuilder.put(entry.getKey(), entry.getValue().createTransactionChain());
+        }
+        long chainId = chainNum.getAndIncrement();
+        ImmutableMap<LogicalDatastoreType, DOMStoreTransactionChain> backingChains = backingChainsBuilder.build();
+        LOG.debug("Transactoin chain {} created with listener {}, backing store chains {}", chainId, listener,
+                backingChains);
+        return new DOMDataBrokerTransactionChainImpl(chainId, backingChains, coordinator, listener);
 
     }
 
     @Override
-    public void close() throws Exception {
-
+    public ListenableFuture<RpcResult<TransactionStatus>> commit(final DOMDataWriteTransaction transaction,
+            final Iterable<DOMStoreThreePhaseCommitCohort> cohorts) {
+        LOG.debug("Transaction: {} submitted with cohorts {}.", transaction.getIdentifier(), cohorts);
+        return coordinator.submit(transaction, cohorts, Optional.<DOMDataCommitErrorListener> absent());
     }
 
 }
diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMDataBrokerTransactionChainImpl.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMDataBrokerTransactionChainImpl.java
new file mode 100644 (file)
index 0000000..b9f096a
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.sal.dom.broker.impl;
+
+import java.util.concurrent.atomic.AtomicLong;
+
+import javax.annotation.concurrent.GuardedBy;
+
+import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
+import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain;
+import org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCohort;
+import org.opendaylight.controller.sal.core.spi.data.DOMStoreTransactionChain;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.util.concurrent.ListenableFuture;
+
+/**
+ * NormalizedNode implementation of {@link org.opendaylight.controller.md.sal.common.api.data.TransactionChain} which is backed
+ * by several {@link DOMStoreTransactionChain} differentiated by provided
+ * {@link org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType} type.
+ *
+ */
+public class DOMDataBrokerTransactionChainImpl extends AbstractDOMForwardedTransactionFactory<DOMStoreTransactionChain>
+        implements DOMTransactionChain, DOMDataCommitErrorListener {
+
+    private static final Logger LOG = LoggerFactory.getLogger(DOMDataBrokerTransactionChainImpl.class);
+    private final DOMDataCommitExecutor coordinator;
+    private final TransactionChainListener listener;
+    private final long chainId;
+    private final AtomicLong txNum = new AtomicLong();
+    @GuardedBy("this")
+    private boolean failed = false;
+
+    /**
+     *
+     * @param chainId
+     *            ID of transaction chain
+     * @param chains
+     *            Backing {@link DOMStoreTransactionChain}s.
+     * @param coordinator
+     *            Commit Coordinator which should be used to coordinate commits
+     *            of transaction
+     *            produced by this chain.
+     * @param listener
+     *            Listener, which listens on transaction chain events.
+     * @throws NullPointerException
+     *             If any of arguments is null.
+     */
+    public DOMDataBrokerTransactionChainImpl(final long chainId,
+            final ImmutableMap<LogicalDatastoreType, DOMStoreTransactionChain> chains,
+            final DOMDataCommitExecutor coordinator, final TransactionChainListener listener) {
+        super(chains);
+        this.chainId = chainId;
+        this.coordinator = Preconditions.checkNotNull(coordinator);
+        this.listener = Preconditions.checkNotNull(listener);
+    }
+
+    @Override
+    protected Object newTransactionIdentifier() {
+        return "DOM-CHAIN-" + chainId + "-" + txNum.getAndIncrement();
+    }
+
+    @Override
+    public synchronized ListenableFuture<RpcResult<TransactionStatus>> commit(
+            final DOMDataWriteTransaction transaction, final Iterable<DOMStoreThreePhaseCommitCohort> cohorts) {
+        return coordinator.submit(transaction, cohorts, Optional.<DOMDataCommitErrorListener> of(this));
+    }
+
+    @Override
+    public synchronized void close() {
+        super.close();
+        for (DOMStoreTransactionChain subChain : getTxFactories().values()) {
+            subChain.close();
+        }
+
+        if (!failed) {
+            LOG.debug("Transaction chain {} successfully finished.", this);
+            listener.onTransactionChainSuccessful(this);
+        }
+    }
+
+    @Override
+    public synchronized void onCommitFailed(final DOMDataWriteTransaction tx, final Throwable cause) {
+        failed = true;
+        LOG.debug("Transaction chain {} failed.", this, cause);
+        listener.onTransactionChainFailed(this, tx, cause);
+    }
+}
diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMDataCommitCoordinatorImpl.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMDataCommitCoordinatorImpl.java
new file mode 100644 (file)
index 0000000..540e2fe
--- /dev/null
@@ -0,0 +1,409 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.sal.dom.broker.impl;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+
+import javax.annotation.concurrent.GuardedBy;
+
+import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
+import org.opendaylight.controller.sal.common.util.Rpcs;
+import org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCohort;
+import org.opendaylight.yangtools.yang.common.RpcError;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.base.Throwables;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableList.Builder;
+import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.ListeningExecutorService;
+
+/**
+ *
+ * Implementation of blocking three phase commit coordinator, which which
+ * supports coordination on multiple {@link DOMStoreThreePhaseCommitCohort}.
+ *
+ * This implementation does not support cancelation of commit,
+ *
+ * In order to advance to next phase of three phase commit all subtasks of
+ * previous step must be finish.
+ *
+ * This executor does not have an upper bound on subtask timeout.
+ *
+ *
+ */
+public class DOMDataCommitCoordinatorImpl implements DOMDataCommitExecutor {
+
+    private static final Logger LOG = LoggerFactory.getLogger(DOMDataCommitCoordinatorImpl.class);
+
+    /**
+     * Runs AND binary operation between all booleans in supplied iteration of booleans.
+     *
+     * This method will stop evaluating iterables if first found is false.
+     */
+    private static final Function<Iterable<Boolean>, Boolean> AND_FUNCTION = new Function<Iterable<Boolean>, Boolean>() {
+
+        @Override
+        public Boolean apply(final Iterable<Boolean> input) {
+            for(boolean value : input) {
+               if(!value) {
+                   return Boolean.FALSE;
+               }
+            }
+            return Boolean.TRUE;
+        }
+    };
+
+    private final ListeningExecutorService executor;
+
+    /**
+     *
+     * Construct DOMDataCommitCoordinator which uses supplied executor to
+     * process commit coordinations.
+     *
+     * @param executor
+     */
+    public DOMDataCommitCoordinatorImpl(final ListeningExecutorService executor) {
+        this.executor = Preconditions.checkNotNull(executor, "executor must not be null.");
+    }
+
+    @Override
+    public ListenableFuture<RpcResult<TransactionStatus>> submit(final DOMDataWriteTransaction transaction,
+            final Iterable<DOMStoreThreePhaseCommitCohort> cohorts, final Optional<DOMDataCommitErrorListener> listener) {
+        Preconditions.checkArgument(transaction != null, "Transaction must not be null.");
+        Preconditions.checkArgument(cohorts != null, "Cohorts must not be null.");
+        Preconditions.checkArgument(listener != null, "Listener must not be null");
+        LOG.debug("Tx: {} is submitted for execution.", transaction.getIdentifier());
+        ListenableFuture<RpcResult<TransactionStatus>> commitFuture = executor.submit(new CommitCoordinationTask(
+                transaction, cohorts, listener));
+        if (listener.isPresent()) {
+            Futures.addCallback(commitFuture, new DOMDataCommitErrorInvoker(transaction, listener.get()));
+        }
+        return commitFuture;
+    }
+
+    /**
+     *
+     * Phase of 3PC commit
+     *
+     * Represents phase of 3PC Commit
+     *
+     *
+     */
+    private static enum CommitPhase {
+        /**
+         *
+         * Commit Coordination Task is submitted for executing
+         *
+         */
+        SUBMITTED,
+        /**
+         * Commit Coordination Task is in can commit phase of 3PC
+         *
+         */
+        CAN_COMMIT,
+        /**
+         * Commit Coordination Task is in pre-commit phase of 3PC
+         *
+         */
+        PRE_COMMIT,
+        /**
+         * Commit Coordination Task is in commit phase of 3PC
+         *
+         */
+        COMMIT,
+        /**
+         * Commit Coordination Task is in abort phase of 3PC
+         *
+         */
+        ABORT
+    }
+
+    /**
+     *
+     * Implementation of blocking three-phase commit-coordination tasks without
+     * support of cancelation.
+     *
+     */
+    private static class CommitCoordinationTask implements Callable<RpcResult<TransactionStatus>> {
+
+        private final DOMDataWriteTransaction tx;
+        private final Iterable<DOMStoreThreePhaseCommitCohort> cohorts;
+
+        @GuardedBy("this")
+        private CommitPhase currentPhase;
+
+        public CommitCoordinationTask(final DOMDataWriteTransaction transaction,
+                final Iterable<DOMStoreThreePhaseCommitCohort> cohorts,
+                final Optional<DOMDataCommitErrorListener> listener) {
+            this.tx = Preconditions.checkNotNull(transaction, "transaction must not be null");
+            this.cohorts = Preconditions.checkNotNull(cohorts, "cohorts must not be null");
+            this.currentPhase = CommitPhase.SUBMITTED;
+        }
+
+        @Override
+        public RpcResult<TransactionStatus> call() throws TransactionCommitFailedException {
+
+            try {
+                canCommitBlocking();
+                preCommitBlocking();
+                return commitBlocking();
+            } catch (TransactionCommitFailedException e) {
+                LOG.warn("Tx: {} Error during phase {}, starting Abort", tx.getIdentifier(), currentPhase, e);
+                abortBlocking(e);
+                throw e;
+            }
+        }
+
+        /**
+         *
+         * Invokes canCommit on underlying cohorts and blocks till
+         * all results are returned.
+         *
+         * Valid state transition is from SUBMITTED to CAN_COMMIT,
+         * if currentPhase is not SUBMITTED throws IllegalStateException.
+         *
+         * @throws TransactionCommitFailedException
+         *             If one of cohorts failed can Commit
+         *
+         */
+        private void canCommitBlocking() throws TransactionCommitFailedException {
+            final Boolean canCommitResult = canCommitAll().checkedGet();
+            if (!canCommitResult) {
+                throw new TransactionCommitFailedException("Can Commit failed, no detailed cause available.");
+            }
+        }
+
+        /**
+         *
+         * Invokes preCommit on underlying cohorts and blocks till
+         * all results are returned.
+         *
+         * Valid state transition is from CAN_COMMIT to PRE_COMMIT, if current
+         * state is not CAN_COMMIT
+         * throws IllegalStateException.
+         *
+         * @throws TransactionCommitFailedException
+         *             If one of cohorts failed preCommit
+         *
+         */
+        private void preCommitBlocking() throws TransactionCommitFailedException {
+            preCommitAll().checkedGet();
+        }
+
+        /**
+         *
+         * Invokes commit on underlying cohorts and blocks till
+         * all results are returned.
+         *
+         * Valid state transition is from PRE_COMMIT to COMMIT, if not throws
+         * IllegalStateException.
+         *
+         * @throws TransactionCommitFailedException
+         *             If one of cohorts failed preCommit
+         *
+         */
+        private RpcResult<TransactionStatus> commitBlocking() throws TransactionCommitFailedException {
+            commitAll().checkedGet();
+            return Rpcs.getRpcResult(true, TransactionStatus.COMMITED, Collections.<RpcError> emptySet());
+        }
+
+        /**
+         * Aborts transaction.
+         *
+         * Invokes {@link DOMStoreThreePhaseCommitCohort#abort()} on all
+         * cohorts, blocks
+         * for all results. If any of the abort failed throws
+         * IllegalStateException,
+         * which will contains originalCause as suppressed Exception.
+         *
+         * If aborts we're successful throws supplied exception
+         *
+         * @param originalCause
+         *            Exception which should be used to fail transaction for
+         *            consumers of transaction
+         *            future and listeners of transaction failure.
+         * @throws TransactionCommitFailedException
+         *             on invocation of this method.
+         *             originalCa
+         * @throws IllegalStateException
+         *             if abort failed.
+         */
+        private void abortBlocking(final TransactionCommitFailedException originalCause)
+                throws TransactionCommitFailedException {
+            LOG.warn("Tx: {} Error during phase {}, starting Abort", tx.getIdentifier(), currentPhase, originalCause);
+            Exception cause = originalCause;
+            try {
+                abortAsyncAll().get();
+            } catch (InterruptedException | ExecutionException e) {
+                LOG.error("Tx: {} Error during Abort.", tx.getIdentifier(), e);
+                cause = new IllegalStateException("Abort failed.", e);
+                cause.addSuppressed(e);
+            }
+            Throwables.propagateIfPossible(cause, TransactionCommitFailedException.class);
+        }
+
+        /**
+         *
+         * Invokes preCommit on underlying cohorts and returns future
+         * which will complete once all preCommit on cohorts completed or
+         * failed.
+         *
+         *
+         * Valid state transition is from CAN_COMMIT to PRE_COMMIT, if current
+         * state is not CAN_COMMIT
+         * throws IllegalStateException.
+         *
+         * @return Future which will complete once all cohorts completed
+         *         preCommit.
+         *         Future throws TransactionCommitFailedException
+         *         If any of cohorts failed preCommit
+         *
+         */
+        private CheckedFuture<Void, TransactionCommitFailedException> preCommitAll() {
+            changeStateFrom(CommitPhase.CAN_COMMIT, CommitPhase.PRE_COMMIT);
+            Builder<ListenableFuture<Void>> ops = ImmutableList.builder();
+            for (DOMStoreThreePhaseCommitCohort cohort : cohorts) {
+                ops.add(cohort.preCommit());
+            }
+            /*
+             * We are returing all futures as list, not only succeeded ones in
+             * order to fail composite future if any of them failed.
+             * See Futures.allAsList for this description.
+             */
+            @SuppressWarnings({ "unchecked", "rawtypes" })
+            ListenableFuture<Void> compositeResult = (ListenableFuture) Futures.allAsList(ops.build());
+            return Futures.makeChecked(compositeResult, TransactionCommitFailedExceptionMapper.PRE_COMMIT_MAPPER);
+        }
+
+        /**
+         *
+         * Invokes commit on underlying cohorts and returns future which
+         * completes
+         * once all commits on cohorts are completed.
+         *
+         * Valid state transition is from PRE_COMMIT to COMMIT, if not throws
+         * IllegalStateException
+         *
+         * @return Future which will complete once all cohorts completed
+         *         commit.
+         *         Future throws TransactionCommitFailedException
+         *         If any of cohorts failed preCommit
+         *
+         */
+        private CheckedFuture<Void, TransactionCommitFailedException> commitAll() {
+            changeStateFrom(CommitPhase.PRE_COMMIT, CommitPhase.COMMIT);
+            Builder<ListenableFuture<Void>> ops = ImmutableList.builder();
+            for (DOMStoreThreePhaseCommitCohort cohort : cohorts) {
+                ops.add(cohort.commit());
+            }
+            /*
+             * We are returing all futures as list, not only succeeded ones in
+             * order to fail composite future if any of them failed.
+             * See Futures.allAsList for this description.
+             */
+            @SuppressWarnings({ "unchecked", "rawtypes" })
+            ListenableFuture<Void> compositeResult = (ListenableFuture) Futures.allAsList(ops.build());
+            return Futures.makeChecked(compositeResult, TransactionCommitFailedExceptionMapper.COMMIT_ERROR_MAPPER);
+        }
+
+        /**
+         *
+         * Invokes canCommit on underlying cohorts and returns composite future
+         * which will contains {@link Boolean#TRUE} only and only if
+         * all cohorts returned true.
+         *
+         * Valid state transition is from SUBMITTED to CAN_COMMIT,
+         * if currentPhase is not SUBMITTED throws IllegalStateException.
+         *
+         * @return Future which will complete once all cohorts completed
+         *         preCommit.
+         *         Future throws TransactionCommitFailedException
+         *         If any of cohorts failed preCommit
+         *
+         */
+        private CheckedFuture<Boolean, TransactionCommitFailedException> canCommitAll() {
+            changeStateFrom(CommitPhase.SUBMITTED, CommitPhase.CAN_COMMIT);
+            Builder<ListenableFuture<Boolean>> canCommitOperations = ImmutableList.builder();
+            for (DOMStoreThreePhaseCommitCohort cohort : cohorts) {
+                canCommitOperations.add(cohort.canCommit());
+            }
+            ListenableFuture<List<Boolean>> allCanCommits = Futures.allAsList(canCommitOperations.build());
+            ListenableFuture<Boolean> allSuccessFuture = Futures.transform(allCanCommits, AND_FUNCTION);
+            return Futures
+                    .makeChecked(allSuccessFuture, TransactionCommitFailedExceptionMapper.CAN_COMMIT_ERROR_MAPPER);
+
+        }
+
+        /**
+         *
+         * Invokes abort on underlying cohorts and returns future which
+         * completes
+         * once all abort on cohorts are completed.
+         *
+         * @return Future which will complete once all cohorts completed
+         *         abort.
+         *
+         */
+        private ListenableFuture<Void> abortAsyncAll() {
+            changeStateFrom(currentPhase, CommitPhase.ABORT);
+            Builder<ListenableFuture<Void>> ops = ImmutableList.builder();
+            for (DOMStoreThreePhaseCommitCohort cohort : cohorts) {
+                ops.add(cohort.abort());
+            }
+            /*
+             * We are returing all futures as list, not only succeeded ones in
+             * order to fail composite future if any of them failed.
+             * See Futures.allAsList for this description.
+             */
+            @SuppressWarnings({ "unchecked", "rawtypes" })
+            ListenableFuture<Void> compositeResult = (ListenableFuture) Futures.allAsList(ops.build());
+            return compositeResult;
+        }
+
+        /**
+         * Change phase / state of transaction from expected value to new value
+         *
+         * This method checks state and updates state to new state of
+         * of this task if current state equals expected state.
+         * If expected state and current state are different raises
+         * IllegalStateException
+         * which means there is probably bug in implementation of commit
+         * coordination.
+         *
+         * If transition is successful, it logs transition on DEBUG level.
+         *
+         * @param currentExpected
+         *            Required phase for change of state
+         * @param newState
+         *            New Phase which will be entered by transaction.
+         * @throws IllegalStateException
+         *             If currentState of task does not match expected state
+         */
+        private synchronized void changeStateFrom(final CommitPhase currentExpected, final CommitPhase newState) {
+            Preconditions.checkState(currentPhase.equals(currentExpected),
+                    "Invalid state transition: Tx: %s current state: %s new state: %s", tx.getIdentifier(),
+                    currentPhase, newState);
+            LOG.debug("Transaction {}: Phase {} Started ", tx.getIdentifier(), newState);
+            currentPhase = newState;
+        };
+
+    }
+
+}
diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMDataCommitErrorInvoker.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMDataCommitErrorInvoker.java
new file mode 100644 (file)
index 0000000..811d4d8
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.sal.dom.broker.impl;
+
+import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+
+import com.google.common.base.Preconditions;
+import com.google.common.util.concurrent.FutureCallback;
+
+/**
+ *
+ * Utility implemetation of {@link FutureCallback} which is responsible
+ * for invoking {@link DOMDataCommitErrorListener} on TransactionCommit failed.
+ *
+ * When {@link #onFailure(Throwable)} is invoked, supplied {@link DOMDataCommitErrorListener}
+ * callback is invoked with associated transaction and throwable is invoked on listener.
+ *
+ */
+class DOMDataCommitErrorInvoker implements FutureCallback<RpcResult<TransactionStatus>> {
+
+    private final DOMDataWriteTransaction tx;
+    private final DOMDataCommitErrorListener listener;
+
+
+    /**
+     *
+     * Construct new DOMDataCommitErrorInvoker.
+     *
+     * @param transaction Transaction which should be passed as argument to {@link DOMDataCommitErrorListener#onCommitFailed(DOMDataWriteTransaction, Throwable)}
+     * @param listener Listener which should be invoked on error.
+     */
+    public DOMDataCommitErrorInvoker(DOMDataWriteTransaction transaction, DOMDataCommitErrorListener listener) {
+        this.tx = Preconditions.checkNotNull(transaction, "Transaction must not be null");
+        this.listener = Preconditions.checkNotNull(listener, "Listener must not be null");
+    }
+
+    @Override
+    public void onFailure(Throwable t) {
+        listener.onCommitFailed(tx, t);
+    }
+
+    @Override
+    public void onSuccess(RpcResult<TransactionStatus> result) {
+        // NOOP
+    }
+}
\ No newline at end of file
diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMDataCommitErrorListener.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMDataCommitErrorListener.java
new file mode 100644 (file)
index 0000000..80bc669
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.sal.dom.broker.impl;
+
+import java.util.EventListener;
+
+import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
+
+/**
+ *
+ * Listener on transaction failure which may be passed to
+ * {@link DOMDataCommitExecutor}. This listener is notified during transaction
+ * processing, before result is delivered to other client code outside MD-SAL.
+ * This allows implementors to update their internal state before transaction
+ * failure is visible to client code.
+ *
+ * This is internal API for MD-SAL implementations, for consumer facing error
+ * listeners see {@link org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener}.
+ *
+ */
+interface DOMDataCommitErrorListener extends EventListener {
+
+    /**
+     *
+     * Callback which is invoked on transaction failure during three phase
+     * commit in {@link DOMDataCommitExecutor}.
+     *
+     *
+     * Implementation of this callback MUST NOT do any blocking calls or any
+     * calls to MD-SAL, since this callback is invoked synchronously on MD-SAL
+     * Broker coordination thread.
+     *
+     * @param tx
+     *            Transaction which failed
+     * @param cause
+     *            Failure reason
+     */
+    void onCommitFailed(DOMDataWriteTransaction tx, Throwable cause);
+
+}
diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMDataCommitExecutor.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMDataCommitExecutor.java
new file mode 100644 (file)
index 0000000..2050d14
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.sal.dom.broker.impl;
+
+import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
+import org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCohort;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+
+import com.google.common.base.Optional;
+import com.google.common.util.concurrent.ListenableFuture;
+
+/**
+ * Executor of Three Phase Commit coordination for
+ * {@link DOMDataWriteTransaction} transactions.
+ *
+ * Implementations are responsible for executing implementation of three-phase
+ * commit protocol on supplied {@link DOMStoreThreePhaseCommitCohort}s.
+ *
+ *
+ */
+interface DOMDataCommitExecutor {
+
+    /**
+     * Submits supplied transaction to be executed in context of provided
+     * cohorts.
+     *
+     * Transaction is used only as a context, cohorts should be associated with
+     * this transaction.
+     *
+     * @param tx
+     *            Transaction to be used as context for reporting
+     * @param cohort
+     *            DOM Store cohorts representing provided transaction, its
+     *            subtransactoins.
+     * @param listener
+     *            Error listener which should be notified if transaction failed.
+     * @return ListenableFuture which contains RpcResult with
+     *         {@link TransactionStatus#COMMITED} if commit coordination on
+     *         cohorts finished successfully.
+     *
+     */
+    ListenableFuture<RpcResult<TransactionStatus>> submit(DOMDataWriteTransaction tx,
+            Iterable<DOMStoreThreePhaseCommitCohort> cohort, Optional<DOMDataCommitErrorListener> listener);
+
+}
diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMDataCommitImplementation.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMDataCommitImplementation.java
new file mode 100644 (file)
index 0000000..4906b6e
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.sal.dom.broker.impl;
+
+import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
+import org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCohort;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+
+import com.google.common.util.concurrent.ListenableFuture;
+
+/**
+ *
+ * Implementation prototype of commit method for
+ * {@link DOMForwardedWriteTransaction}.
+ *
+ */
+public interface DOMDataCommitImplementation {
+
+    /**
+     * User-supplied implementation of {@link DOMDataWriteTransaction#commit()}
+     * for transaction.
+     *
+     * Callback invoked when {@link DOMDataWriteTransaction#commit()} is invoked
+     * on transaction created by this factory.
+     *
+     * @param transaction
+     *            Transaction on which {@link DOMDataWriteTransaction#commit()}
+     *            was invoked.
+     * @param cohorts
+     *            Iteration of cohorts for subtransactions associated with
+     *            commited transaction.
+     *
+     */
+    ListenableFuture<RpcResult<TransactionStatus>> commit(final DOMDataWriteTransaction transaction,
+            final Iterable<DOMStoreThreePhaseCommitCohort> cohorts);
+}
+
diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMForwardedReadOnlyTransaction.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMForwardedReadOnlyTransaction.java
new file mode 100644 (file)
index 0000000..d2543f0
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.sal.dom.broker.impl;
+
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataReadTransaction;
+import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadTransaction;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.util.concurrent.ListenableFuture;
+
+/**
+ *
+ * Read Only Transaction, which is composed of several
+ * {@link DOMStoreReadTransaction} transactions. Subtransaction is selected by
+ * {@link LogicalDatastoreType} type parameter in
+ * {@link #read(LogicalDatastoreType, InstanceIdentifier)}.
+ */
+class DOMForwardedReadOnlyTransaction extends
+        AbstractDOMForwardedCompositeTransaction<LogicalDatastoreType, DOMStoreReadTransaction> implements
+        DOMDataReadTransaction {
+
+    protected DOMForwardedReadOnlyTransaction(final Object identifier,
+            final ImmutableMap<LogicalDatastoreType, DOMStoreReadTransaction> backingTxs) {
+        super(identifier, backingTxs);
+    }
+
+    @Override
+    public ListenableFuture<Optional<NormalizedNode<?, ?>>> read(final LogicalDatastoreType store,
+            final InstanceIdentifier path) {
+        return getSubtransaction(store).read(path);
+    }
+
+}
diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMForwardedReadWriteTransaction.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMForwardedReadWriteTransaction.java
new file mode 100644 (file)
index 0000000..f5b96e2
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */package org.opendaylight.controller.md.sal.dom.broker.impl;
+
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction;
+import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadWriteTransaction;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.util.concurrent.ListenableFuture;
+
+/**
+ *
+ * Read-Write Transaction, which is composed of several
+ * {@link DOMStoreReadWriteTransaction} transactions. Subtransaction is selected by
+ * {@link LogicalDatastoreType} type parameter in:
+ *
+ * <ul>
+ * <li>{@link #read(LogicalDatastoreType, InstanceIdentifier)}
+ * <li>{@link #put(LogicalDatastoreType, InstanceIdentifier, NormalizedNode)}
+ * <li>{@link #delete(LogicalDatastoreType, InstanceIdentifier)}
+ * <li>{@link #merge(LogicalDatastoreType, InstanceIdentifier, NormalizedNode)}
+ * </ul>
+ * {@link #commit()} will result in invocation of
+ * {@link DOMDataCommitImplementation#commit(org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction, Iterable)}
+ * invocation with all {@link org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCohort} for underlying
+ * transactions.
+ *
+ */
+
+class DOMForwardedReadWriteTransaction extends DOMForwardedWriteTransaction<DOMStoreReadWriteTransaction> implements
+        DOMDataReadWriteTransaction {
+
+    protected DOMForwardedReadWriteTransaction(final Object identifier,
+            final ImmutableMap<LogicalDatastoreType, DOMStoreReadWriteTransaction> backingTxs,
+            final DOMDataCommitImplementation commitImpl) {
+        super(identifier, backingTxs, commitImpl);
+    }
+
+    @Override
+    public ListenableFuture<Optional<NormalizedNode<?, ?>>> read(final LogicalDatastoreType store,
+            final InstanceIdentifier path) {
+        return getSubtransaction(store).read(path);
+    }
+}
\ No newline at end of file
diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMForwardedWriteTransaction.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMForwardedWriteTransaction.java
new file mode 100644 (file)
index 0000000..eeb345e
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.sal.dom.broker.impl;
+
+import static com.google.common.base.Preconditions.checkState;
+
+import javax.annotation.concurrent.GuardedBy;
+
+import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
+import org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCohort;
+import org.opendaylight.controller.sal.core.spi.data.DOMStoreWriteTransaction;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.util.concurrent.ListenableFuture;
+
+/**
+ *
+ *
+ * Read-Write Transaction, which is composed of several
+ * {@link DOMStoreWriteTransaction} transactions. Subtransaction is selected by
+ * {@link LogicalDatastoreType} type parameter in:
+ *
+ * <ul>
+ * <li>{@link #put(LogicalDatastoreType, InstanceIdentifier, NormalizedNode)}
+ * <li>{@link #delete(LogicalDatastoreType, InstanceIdentifier)}
+ * <li>{@link #merge(LogicalDatastoreType, InstanceIdentifier, NormalizedNode)}
+ * </ul>
+ * <p>
+ * {@link #commit()} will result in invocation of
+ * {@link DOMDataCommitImplementation#commit(org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction, Iterable)}
+ * invocation with all {@link org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCohort} for underlying
+ * transactions.
+ *
+ * @param <T>
+ *            Subtype of {@link DOMStoreWriteTransaction} which is used as
+ *            subtransaction.
+ */
+class DOMForwardedWriteTransaction<T extends DOMStoreWriteTransaction> extends
+        AbstractDOMForwardedCompositeTransaction<LogicalDatastoreType, T> implements DOMDataWriteTransaction {
+
+    @GuardedBy("this")
+    private DOMDataCommitImplementation commitImpl;
+
+    @GuardedBy("this")
+    private boolean canceled;
+    @GuardedBy("this")
+    private ListenableFuture<RpcResult<TransactionStatus>> commitFuture;
+
+    protected DOMForwardedWriteTransaction(final Object identifier,
+            final ImmutableMap<LogicalDatastoreType, T> backingTxs, final DOMDataCommitImplementation commitImpl) {
+        super(identifier, backingTxs);
+        this.commitImpl = Preconditions.checkNotNull(commitImpl, "commitImpl must not be null.");
+    }
+
+    @Override
+    public void put(final LogicalDatastoreType store, final InstanceIdentifier path, final NormalizedNode<?, ?> data) {
+        checkNotReady();
+        getSubtransaction(store).write(path, data);
+    }
+
+    @Override
+    public void delete(final LogicalDatastoreType store, final InstanceIdentifier path) {
+        checkNotReady();
+        getSubtransaction(store).delete(path);
+    }
+
+    @Override
+    public void merge(final LogicalDatastoreType store, final InstanceIdentifier path, final NormalizedNode<?, ?> data) {
+        checkNotReady();
+        getSubtransaction(store).merge(path, data);
+    }
+
+    @Override
+    public synchronized void cancel() {
+        checkState(!canceled, "Transaction was canceled.");
+        if (commitFuture != null) {
+            // FIXME: Implement cancelation of commit future
+            // when Broker impl will support cancelation.
+            throw new UnsupportedOperationException("Not implemented yet.");
+        }
+        canceled = true;
+        commitImpl = null;
+
+    }
+
+    @Override
+    public synchronized ListenableFuture<RpcResult<TransactionStatus>> commit() {
+        checkNotReady();
+
+        ImmutableList.Builder<DOMStoreThreePhaseCommitCohort> cohortsBuilder = ImmutableList.builder();
+        for (DOMStoreWriteTransaction subTx : getSubtransactions()) {
+            cohortsBuilder.add(subTx.ready());
+        }
+        ImmutableList<DOMStoreThreePhaseCommitCohort> cohorts = cohortsBuilder.build();
+        commitFuture = commitImpl.commit(this, cohorts);
+        return commitFuture;
+    }
+
+    private void checkNotReady() {
+        checkNotCanceled();
+        checkNotCommited();
+    }
+
+    private void checkNotCanceled() {
+        Preconditions.checkState(!canceled, "Transaction was canceled.");
+    }
+
+    private void checkNotCommited() {
+        checkState(commitFuture == null, "Transaction was already commited.");
+    }
+
+}
\ No newline at end of file
diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/TransactionCommitFailedExceptionMapper.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/TransactionCommitFailedExceptionMapper.java
new file mode 100644 (file)
index 0000000..258b068
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.sal.dom.broker.impl;
+
+import java.util.concurrent.ExecutionException;
+
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
+
+import com.google.common.base.Function;
+import com.google.common.base.Preconditions;
+
+/**
+ *
+ * Utility exception mapper which translates {@link Exception}
+ * to {@link TransactionCommitFailedException}.
+ *
+ * This mapper is intended to be used with {@link com.google.common.util.concurrent.Futures#makeChecked(com.google.common.util.concurrent.ListenableFuture, Function)}
+ * <ul>
+ * <li>if exception is {@link TransactionCommitFailedException} or one of its subclasses returns original exception.
+ * <li>if exception is {@link ExecutionException} and cause is  {@link TransactionCommitFailedException} return cause
+ * <li>otherwise returns {@link TransactionCommitFailedException} with original exception as a cause.
+ * </ul>
+ *
+ */
+
+final class TransactionCommitFailedExceptionMapper implements
+        Function<Exception, TransactionCommitFailedException> {
+
+    static final TransactionCommitFailedExceptionMapper PRE_COMMIT_MAPPER = create("canCommit");
+
+    static final TransactionCommitFailedExceptionMapper CAN_COMMIT_ERROR_MAPPER = create("preCommit");
+
+    static final TransactionCommitFailedExceptionMapper COMMIT_ERROR_MAPPER = create("commit");
+
+    private final String opName;
+
+    private TransactionCommitFailedExceptionMapper(final String opName) {
+        this.opName = Preconditions.checkNotNull(opName);
+    }
+
+    public static final TransactionCommitFailedExceptionMapper create(final String opName) {
+        return new TransactionCommitFailedExceptionMapper(opName);
+    }
+
+    @Override
+    public TransactionCommitFailedException apply(final Exception e) {
+        // If excetion is TransactionCommitFailedException
+        // we reuse it directly.
+        if (e instanceof TransactionCommitFailedException) {
+            return (TransactionCommitFailedException) e;
+        }
+        // If error is ExecutionException which was caused by cause of
+        // TransactionCommitFailedException
+        // we reuse original cause
+        if (e instanceof ExecutionException && e.getCause() instanceof TransactionCommitFailedException) {
+            return (TransactionCommitFailedException) e.getCause();
+        }
+        if (e instanceof InterruptedException) {
+            return new TransactionCommitFailedException(opName + " failed - DOMStore was interupted.", e);
+        }
+        // Otherwise we are using new exception, with original cause
+        return new TransactionCommitFailedException(opName + " failed", e);
+    }
+}
\ No newline at end of file
index 10b838a2c6122a2d8e629f7ce02f3698fe90703c..b0c4274fa57ddaf151dceca039890c60ac44b59a 100644 (file)
@@ -17,12 +17,15 @@ import javax.annotation.concurrent.GuardedBy;
 
 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeListener;
+import org.opendaylight.controller.md.sal.common.api.data.OptimisticLockFailedException;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
 import org.opendaylight.controller.md.sal.dom.store.impl.SnapshotBackedWriteTransaction.TransactionReadyPrototype;
-import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataPreconditionFailedException;
+import org.opendaylight.controller.md.sal.dom.store.impl.tree.ConflictingModificationAppliedException;
 import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataTree;
 import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataTreeCandidate;
 import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataTreeModification;
 import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataTreeSnapshot;
+import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataValidationFailedException;
 import org.opendaylight.controller.md.sal.dom.store.impl.tree.ListenerTree;
 import org.opendaylight.controller.md.sal.dom.store.impl.tree.data.InMemoryDataTreeFactory;
 import org.opendaylight.controller.sal.core.spi.data.DOMStore;
@@ -302,15 +305,19 @@ public class InMemoryDOMDataStore implements DOMStore, Identifiable<String>, Sch
         public ListenableFuture<Boolean> canCommit() {
             return executor.submit(new Callable<Boolean>() {
                 @Override
-                public Boolean call() {
+                public Boolean call() throws TransactionCommitFailedException {
                     try {
                         dataTree.validate(modification);
                         LOG.debug("Store Transaction: {} can be committed", transaction.getIdentifier());
                         return true;
-                    } catch (DataPreconditionFailedException e) {
+                    } catch (ConflictingModificationAppliedException e) {
+                        LOG.warn("Store Tx: {} Conflicting modification for {}.", transaction.getIdentifier(),
+                                e.getPath());
+                        throw new OptimisticLockFailedException("Optimistic lock failed.",e);
+                    } catch (DataValidationFailedException e) {
                         LOG.warn("Store Tx: {} Data Precondition failed for {}.", transaction.getIdentifier(),
                                 e.getPath(), e);
-                        return false;
+                        throw new TransactionCommitFailedException("Data did not pass validation.",e);
                     }
                 }
             });
diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/ConflictingModificationAppliedException.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/ConflictingModificationAppliedException.java
new file mode 100644 (file)
index 0000000..3625d33
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.sal.dom.store.impl.tree;
+
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+
+/**
+ * Exception thrown when a proposed change fails validation before being
+ * applied into the Data Tree because the Data Tree has been modified
+ * in way that a conflicting
+ * node is present.
+ */
+public class ConflictingModificationAppliedException extends DataValidationFailedException {
+
+    /**
+     *
+     */
+    private static final long serialVersionUID = 1L;
+
+    public ConflictingModificationAppliedException(final InstanceIdentifier path, final String message, final Throwable cause) {
+        super(path, message, cause);
+    }
+
+    public ConflictingModificationAppliedException(final InstanceIdentifier path, final String message) {
+        super(path, message);
+    }
+
+}
index ee9726a4506439f97142817aba7506e4380ebbd8..4807e15653d017fa9f341f8a6afc4cf6a9191c61 100644 (file)
@@ -32,7 +32,7 @@ public interface DataTree {
     /**
      * Validate whether a particular modification can be applied to the data tree.
      */
-    void validate(DataTreeModification modification) throws DataPreconditionFailedException;
+    void validate(DataTreeModification modification) throws DataValidationFailedException;
 
     /**
      * Prepare a modification for commit.
@@ -17,7 +17,7 @@ import com.google.common.base.Preconditions;
  * the datastore has been concurrently modified such that a conflicting
  * node is present, or the modification is structurally incorrect.
  */
-public class DataPreconditionFailedException extends Exception {
+public class DataValidationFailedException extends Exception {
     private static final long serialVersionUID = 1L;
     private final InstanceIdentifier path;
 
@@ -27,7 +27,7 @@ public class DataPreconditionFailedException extends Exception {
      * @param path Object path which caused this exception
      * @param message Specific message describing the failure
      */
-    public DataPreconditionFailedException(final InstanceIdentifier path, final String message) {
+    public DataValidationFailedException(final InstanceIdentifier path, final String message) {
         this(path, message, null);
     }
     /**
@@ -37,7 +37,7 @@ public class DataPreconditionFailedException extends Exception {
      * @param message Specific message describing the failure
      * @param cause Exception which triggered this failure, may be null
      */
-    public DataPreconditionFailedException(final InstanceIdentifier path, final String message, final Throwable cause) {
+    public DataValidationFailedException(final InstanceIdentifier path, final String message, final Throwable cause) {
         super(message, cause);
         this.path = Preconditions.checkNotNull(path);
     }
diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/IncorrectDataStructureException.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/IncorrectDataStructureException.java
new file mode 100644 (file)
index 0000000..87482a9
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.sal.dom.store.impl.tree;
+
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+
+/**
+ * Exception thrown when a proposed change fails validation before being
+ * applied into the datastore because of incorrect structure of user supplied
+ * data.
+ *
+ */
+public class IncorrectDataStructureException extends DataValidationFailedException {
+
+    /**
+     *
+     */
+    private static final long serialVersionUID = 1L;
+
+    public IncorrectDataStructureException(final InstanceIdentifier path, final String message, final Throwable cause) {
+        super(path, message, cause);
+    }
+
+    public IncorrectDataStructureException(final InstanceIdentifier path, final String message) {
+        super(path, message);
+    }
+
+}
index d3495b542a25f4a05ffa1a2f83e92808c56e6ca3..4ffa6f91b03be92e18e09a6b1c01d5689c338584 100644 (file)
@@ -10,7 +10,7 @@ package org.opendaylight.controller.md.sal.dom.store.impl.tree.data;
 import java.util.concurrent.locks.ReadWriteLock;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
 
-import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataPreconditionFailedException;
+import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataValidationFailedException;
 import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataTree;
 import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataTreeCandidate;
 import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataTreeModification;
@@ -81,7 +81,7 @@ final class InMemoryDataTree implements DataTree {
     }
 
     @Override
-    public void validate(final DataTreeModification modification) throws DataPreconditionFailedException {
+    public void validate(final DataTreeModification modification) throws DataValidationFailedException {
         Preconditions.checkArgument(modification instanceof InMemoryDataTreeModification, "Invalid modification class %s", modification.getClass());
 
         final InMemoryDataTreeModification m = (InMemoryDataTreeModification)modification;
index df03db35bec44bc6216cdfe760c0853ce6cda141..f72d57519472f79d8e6ab39528e9b22c10b42702 100644 (file)
@@ -7,7 +7,7 @@
  */
 package org.opendaylight.controller.md.sal.dom.store.impl.tree.data;
 
-import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataPreconditionFailedException;
+import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataValidationFailedException;
 import org.opendaylight.controller.md.sal.dom.store.impl.tree.StoreTreeNode;
 import org.opendaylight.controller.md.sal.dom.store.impl.tree.spi.TreeNode;
 import org.opendaylight.controller.md.sal.dom.store.impl.tree.spi.Version;
@@ -87,7 +87,7 @@ interface ModificationApplyOperation extends StoreTreeNode<ModificationApplyOper
      * @param current Metadata Node to which modification should be applied
      * @return true if modification is applicable
      *         false if modification is no applicable
-     * @throws DataPreconditionFailedException
+     * @throws DataValidationFailedException
      */
-    void checkApplicable(InstanceIdentifier path, NodeModification modification, Optional<TreeNode> current) throws DataPreconditionFailedException;
+    void checkApplicable(InstanceIdentifier path, NodeModification modification, Optional<TreeNode> current) throws DataValidationFailedException;
 }
index 5c6aeace569aabd1020a1b67e4572e428dbf2da1..1d10ab6ea5a971dfc3e4a160949fd6f5c17fd30b 100644 (file)
@@ -11,7 +11,7 @@ import static com.google.common.base.Preconditions.checkArgument;
 
 import java.util.Map;
 
-import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataPreconditionFailedException;
+import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataValidationFailedException;
 import org.opendaylight.controller.md.sal.dom.store.impl.tree.ModificationType;
 import org.opendaylight.controller.md.sal.dom.store.impl.tree.data.DataNodeContainerModificationStrategy.ListEntryModificationStrategy;
 import org.opendaylight.controller.md.sal.dom.store.impl.tree.data.ValueNodeModificationStrategy.LeafSetEntryModificationStrategy;
@@ -67,7 +67,7 @@ abstract class NormalizedNodeContainerModificationStrategy extends SchemaAwareAp
 
     @Override
     protected void checkWriteApplicable(final InstanceIdentifier path, final NodeModification modification,
-            final Optional<TreeNode> current) throws DataPreconditionFailedException {
+            final Optional<TreeNode> current) throws DataValidationFailedException {
         // FIXME: Implement proper write check for replacement of node container
         //        prerequisite is to have transaction chain available for clients
         //        otherwise this will break chained writes to same node.
@@ -166,12 +166,12 @@ abstract class NormalizedNodeContainerModificationStrategy extends SchemaAwareAp
 
     @Override
     protected void checkSubtreeModificationApplicable(final InstanceIdentifier path, final NodeModification modification,
-            final Optional<TreeNode> current) throws DataPreconditionFailedException {
-        checkDataPrecondition(path, current.isPresent(), "Node was deleted by other transaction.");
+            final Optional<TreeNode> current) throws DataValidationFailedException {
+        checkConflicting(path, current.isPresent(), "Node was deleted by other transaction.");
         checkChildPreconditions(path, modification, current);
     }
 
-    private void checkChildPreconditions(final InstanceIdentifier path, final NodeModification modification, final Optional<TreeNode> current) throws DataPreconditionFailedException {
+    private void checkChildPreconditions(final InstanceIdentifier path, final NodeModification modification, final Optional<TreeNode> current) throws DataValidationFailedException {
         final TreeNode currentMeta = current.get();
         for (NodeModification childMod : modification.getChildren()) {
             final PathArgument childId = childMod.getIdentifier();
@@ -184,7 +184,7 @@ abstract class NormalizedNodeContainerModificationStrategy extends SchemaAwareAp
 
     @Override
     protected void checkMergeApplicable(final InstanceIdentifier path, final NodeModification modification,
-            final Optional<TreeNode> current) throws DataPreconditionFailedException {
+            final Optional<TreeNode> current) throws DataValidationFailedException {
         if(current.isPresent()) {
             checkChildPreconditions(path, modification,current);
         }
index 6ef76adacf9cc478f36b5c9914b9704b16ffd05c..f6006359afea6ef4bdc32fe1bc609e3472e6d49f 100644 (file)
@@ -11,7 +11,9 @@ import static com.google.common.base.Preconditions.checkArgument;
 
 import java.util.List;
 
-import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataPreconditionFailedException;
+import org.opendaylight.controller.md.sal.dom.store.impl.tree.ConflictingModificationAppliedException;
+import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataValidationFailedException;
+import org.opendaylight.controller.md.sal.dom.store.impl.tree.IncorrectDataStructureException;
 import org.opendaylight.controller.md.sal.dom.store.impl.tree.ModificationType;
 import org.opendaylight.controller.md.sal.dom.store.impl.tree.data.DataNodeContainerModificationStrategy.ContainerModificationStrategy;
 import org.opendaylight.controller.md.sal.dom.store.impl.tree.data.DataNodeContainerModificationStrategy.UnkeyedListItemModificationStrategy;
@@ -82,9 +84,9 @@ abstract class SchemaAwareApplyOperation implements ModificationApplyOperation {
         return null;
     }
 
-    public static boolean checkDataPrecondition(final InstanceIdentifier path, final boolean condition, final String message) throws DataPreconditionFailedException {
+    public static boolean checkConflicting(final InstanceIdentifier path, final boolean condition, final String message) throws ConflictingModificationAppliedException {
         if(!condition) {
-            throw new DataPreconditionFailedException(path, message);
+            throw new ConflictingModificationAppliedException(path, message);
         }
         return condition;
     }
@@ -109,10 +111,10 @@ abstract class SchemaAwareApplyOperation implements ModificationApplyOperation {
         }
     }
 
-    private static final void checkNotConflicting(final InstanceIdentifier path, final TreeNode original, final TreeNode current) throws DataPreconditionFailedException {
-        checkDataPrecondition(path, original.getVersion().equals(current.getVersion()),
+    private static final void checkNotConflicting(final InstanceIdentifier path, final TreeNode original, final TreeNode current) throws ConflictingModificationAppliedException {
+        checkConflicting(path, original.getVersion().equals(current.getVersion()),
                 "Node was replaced by other transaction.");
-        checkDataPrecondition(path, original.getSubtreeVersion().equals(current.getSubtreeVersion()),
+        checkConflicting(path, original.getSubtreeVersion().equals(current.getSubtreeVersion()),
                 "Node children was modified by other transaction");
     }
 
@@ -130,7 +132,7 @@ abstract class SchemaAwareApplyOperation implements ModificationApplyOperation {
     }
 
     @Override
-    public final void checkApplicable(final InstanceIdentifier path,final NodeModification modification, final Optional<TreeNode> current) throws DataPreconditionFailedException {
+    public final void checkApplicable(final InstanceIdentifier path,final NodeModification modification, final Optional<TreeNode> current) throws DataValidationFailedException {
         switch (modification.getType()) {
         case DELETE:
             checkDeleteApplicable(modification, current);
@@ -151,7 +153,7 @@ abstract class SchemaAwareApplyOperation implements ModificationApplyOperation {
 
     }
 
-    protected void checkMergeApplicable(final InstanceIdentifier path, final NodeModification modification, final Optional<TreeNode> current) throws DataPreconditionFailedException {
+    protected void checkMergeApplicable(final InstanceIdentifier path, final NodeModification modification, final Optional<TreeNode> current) throws DataValidationFailedException {
         Optional<TreeNode> original = modification.getOriginal();
         if (original.isPresent() && current.isPresent()) {
             /*
@@ -166,12 +168,12 @@ abstract class SchemaAwareApplyOperation implements ModificationApplyOperation {
         }
     }
 
-    protected void checkWriteApplicable(final InstanceIdentifier path, final NodeModification modification, final Optional<TreeNode> current) throws DataPreconditionFailedException {
+    protected void checkWriteApplicable(final InstanceIdentifier path, final NodeModification modification, final Optional<TreeNode> current) throws DataValidationFailedException {
         Optional<TreeNode> original = modification.getOriginal();
         if (original.isPresent() && current.isPresent()) {
             checkNotConflicting(path, original.get(), current.get());
         } else if(original.isPresent()) {
-            throw new DataPreconditionFailedException(path,"Node was deleted by other transaction.");
+            throw new ConflictingModificationAppliedException(path,"Node was deleted by other transaction.");
         }
     }
 
@@ -216,8 +218,18 @@ abstract class SchemaAwareApplyOperation implements ModificationApplyOperation {
     protected abstract TreeNode applySubtreeChange(ModifiedNode modification,
             TreeNode currentMeta, Version version);
 
+    /**
+     *
+     * Checks is supplied {@link NodeModification} is applicable for Subtree Modification.
+     *
+     * @param path Path to current node
+     * @param modification Node modification which should be applied.
+     * @param current Current state of data tree
+     * @throws ConflictingModificationAppliedException If subtree was changed in conflicting way
+     * @throws IncorrectDataStructureException If subtree modification is not applicable (e.g. leaf node).
+     */
     protected abstract void checkSubtreeModificationApplicable(InstanceIdentifier path, final NodeModification modification,
-            final Optional<TreeNode> current) throws DataPreconditionFailedException;
+            final Optional<TreeNode> current) throws DataValidationFailedException;
 
     protected abstract void verifyWrittenStructure(NormalizedNode<?, ?> writtenValue);
 
@@ -262,8 +274,8 @@ abstract class SchemaAwareApplyOperation implements ModificationApplyOperation {
 
         @Override
         protected void checkSubtreeModificationApplicable(final InstanceIdentifier path, final NodeModification modification,
-                final Optional<TreeNode> current) throws DataPreconditionFailedException {
-            throw new DataPreconditionFailedException(path, "Subtree modification is not allowed.");
+                final Optional<TreeNode> current) throws IncorrectDataStructureException {
+            throw new IncorrectDataStructureException(path, "Subtree modification is not allowed.");
         }
     }
 }
index a9f69ac953afdfda5d853e47474d09efe0a26021..900fa320a167838a8d04155becb2096385dfaaed 100644 (file)
@@ -9,7 +9,7 @@ package org.opendaylight.controller.md.sal.dom.store.impl.tree.data;
 
 import static com.google.common.base.Preconditions.checkArgument;
 
-import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataPreconditionFailedException;
+import org.opendaylight.controller.md.sal.dom.store.impl.tree.IncorrectDataStructureException;
 import org.opendaylight.controller.md.sal.dom.store.impl.tree.spi.TreeNode;
 import org.opendaylight.controller.md.sal.dom.store.impl.tree.spi.TreeNodeFactory;
 import org.opendaylight.controller.md.sal.dom.store.impl.tree.spi.Version;
@@ -68,8 +68,8 @@ abstract class ValueNodeModificationStrategy<T extends DataSchemaNode> extends S
 
     @Override
     protected void checkSubtreeModificationApplicable(final InstanceIdentifier path, final NodeModification modification,
-            final Optional<TreeNode> current) throws DataPreconditionFailedException {
-        throw new DataPreconditionFailedException(path, "Subtree modification is not allowed.");
+            final Optional<TreeNode> current) throws IncorrectDataStructureException {
+        throw new IncorrectDataStructureException(path, "Subtree modification is not allowed.");
     }
 
     public static class LeafSetEntryModificationStrategy extends ValueNodeModificationStrategy<LeafListSchemaNode> {
index 70db71f3ac961d1fed0a1edd00a6658c0f3f628d..b0ccfb995db612188cff2bbb5014def94911e4d7 100644 (file)
@@ -1,11 +1,13 @@
 package org.opendaylight.controller.sal.dom.broker.osgi;
 
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
 import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
 import org.opendaylight.controller.md.sal.dom.api.DOMDataChangeListener;
 import org.opendaylight.controller.md.sal.dom.api.DOMDataReadTransaction;
 import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction;
 import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
+import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
 import org.osgi.framework.ServiceReference;
@@ -38,4 +40,9 @@ public class DOMDataBrokerProxy extends AbstractBrokerServiceProxy<DOMDataBroker
         return getDelegate().registerDataChangeListener(store, path, listener, triggeringScope);
     }
 
+    @Override
+    public DOMTransactionChain createTransactionChain(final TransactionChainListener listener) {
+        return getDelegate().createTransactionChain(listener);
+    }
+
 }
diff --git a/opendaylight/md-sal/sal-dom-broker/src/test/java/org/opendaylight/controller/md/sal/dom/broker/impl/BlockingTransactionChainListener.java b/opendaylight/md-sal/sal-dom-broker/src/test/java/org/opendaylight/controller/md/sal/dom/broker/impl/BlockingTransactionChainListener.java
new file mode 100644 (file)
index 0000000..5b531fe
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.sal.dom.broker.impl;
+
+import org.opendaylight.controller.md.sal.common.api.data.AsyncTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionChain;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
+
+import com.google.common.util.concurrent.SettableFuture;
+
+/**
+ * Simple implementation of {@link TransactionChainListener} for testing.
+ *
+ * This transaction chain listener does not contain any logic, only update
+ * futures ({@link #getFailFuture()} and {@link #getSuccessFuture()} when
+ * transaction chain event is retrieved.
+ *
+ */
+class BlockingTransactionChainListener implements TransactionChainListener {
+
+    private final SettableFuture<Throwable> failFuture = SettableFuture.create();
+    private final SettableFuture<Void> successFuture = SettableFuture.create();
+
+    @Override
+    public void onTransactionChainFailed(final TransactionChain<?, ?> chain, final AsyncTransaction<?, ?> transaction,
+            final Throwable cause) {
+        failFuture.set(cause);
+    }
+
+    @Override
+    public void onTransactionChainSuccessful(final TransactionChain<?, ?> chain) {
+        successFuture.set(null);
+    }
+
+    public SettableFuture<Throwable> getFailFuture() {
+        return failFuture;
+    }
+
+    public SettableFuture<Void> getSuccessFuture() {
+        return successFuture;
+    }
+
+}
diff --git a/opendaylight/md-sal/sal-dom-broker/src/test/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMTransactionChainTest.java b/opendaylight/md-sal/sal-dom-broker/src/test/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMTransactionChainTest.java
new file mode 100644 (file)
index 0000000..2a955e5
--- /dev/null
@@ -0,0 +1,209 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.sal.dom.broker.impl;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType.CONFIGURATION;
+import static org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType.OPERATIONAL;
+
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataReadTransaction;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction;
+import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain;
+import org.opendaylight.controller.md.sal.dom.store.impl.InMemoryDOMDataStore;
+import org.opendaylight.controller.md.sal.dom.store.impl.TestModel;
+import org.opendaylight.controller.sal.core.spi.data.DOMStore;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+
+import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.common.util.concurrent.MoreExecutors;
+
+public class DOMTransactionChainTest {
+
+    private SchemaContext schemaContext;
+    private DOMDataBrokerImpl domBroker;
+
+    @Before
+    public void setupStore() {
+        InMemoryDOMDataStore operStore = new InMemoryDOMDataStore("OPER", MoreExecutors.sameThreadExecutor());
+        InMemoryDOMDataStore configStore = new InMemoryDOMDataStore("CFG", MoreExecutors.sameThreadExecutor());
+        schemaContext = TestModel.createTestContext();
+
+        operStore.onGlobalContextUpdated(schemaContext);
+        configStore.onGlobalContextUpdated(schemaContext);
+
+        ImmutableMap<LogicalDatastoreType, DOMStore> stores = ImmutableMap.<LogicalDatastoreType, DOMStore> builder() //
+                .put(CONFIGURATION, configStore) //
+                .put(OPERATIONAL, operStore) //
+                .build();
+
+        ListeningExecutorService executor = MoreExecutors.listeningDecorator(Executors.newSingleThreadExecutor());
+        domBroker = new DOMDataBrokerImpl(stores, executor);
+    }
+
+    @Test
+    public void testTransactionChainNoConflict() throws InterruptedException, ExecutionException, TimeoutException {
+        BlockingTransactionChainListener listener = new BlockingTransactionChainListener();
+        DOMTransactionChain txChain = domBroker.createTransactionChain(listener);
+        assertNotNull(txChain);
+
+        /**
+         * We alocate new read-write transaction and write /test
+         *
+         *
+         */
+        DOMDataReadWriteTransaction firstTx = allocateAndWrite(txChain);
+
+        /**
+         * First transaction is marked as ready, we are able to allocate chained
+         * transactions
+         */
+        ListenableFuture<RpcResult<TransactionStatus>> firstWriteTxFuture = firstTx.commit();
+
+        /**
+         * We alocate chained transaction - read transaction.
+         */
+        DOMDataReadTransaction secondReadTx = txChain.newReadOnlyTransaction();
+
+        /**
+         *
+         * We test if we are able to read data from tx, read should not fail
+         * since we are using chained transaction.
+         *
+         *
+         */
+        assertTestContainerExists(secondReadTx);
+
+        /**
+         *
+         * We alocate next transaction, which is still based on first one, but
+         * is read-write.
+         *
+         */
+        DOMDataReadWriteTransaction thirdDeleteTx = allocateAndDelete(txChain);
+
+        /**
+         * third transaction is sealed.
+         */
+        ListenableFuture<RpcResult<TransactionStatus>> thirdDeleteTxFuture = thirdDeleteTx.commit();
+
+        /**
+         * We commit first transaction
+         *
+         */
+        assertCommitSuccessful(firstWriteTxFuture);
+
+        // Alocates store transaction
+        DOMDataReadTransaction storeReadTx = domBroker.newReadOnlyTransaction();
+        /**
+         * We verify transaction is commited to store, container should exists
+         * in datastore.
+         */
+        assertTestContainerExists(storeReadTx);
+        /**
+         * We commit third transaction
+         *
+         */
+        assertCommitSuccessful(thirdDeleteTxFuture);
+
+        /**
+         * We close transaction chain.
+         */
+        txChain.close();
+
+        listener.getSuccessFuture().get(1000, TimeUnit.MILLISECONDS);
+    }
+
+    @Test
+    public void testTransactionChainNotSealed() throws InterruptedException, ExecutionException, TimeoutException {
+        BlockingTransactionChainListener listener = new BlockingTransactionChainListener();
+        DOMTransactionChain txChain = domBroker.createTransactionChain(listener);
+        assertNotNull(txChain);
+
+        /**
+         * We alocate new read-write transaction and write /test
+         *
+         *
+         */
+        allocateAndWrite(txChain);
+
+        /**
+         * We alocate chained transaction - read transaction, note first one is
+         * still not commited to datastore, so this allocation should fail with
+         * IllegalStateException.
+         */
+        try {
+            txChain.newReadOnlyTransaction();
+            fail("Allocation of secondReadTx should fail with IllegalStateException");
+        } catch (Exception e) {
+            assertTrue(e instanceof IllegalStateException);
+        }
+    }
+
+    private static DOMDataReadWriteTransaction allocateAndDelete(final DOMTransactionChain txChain)
+            throws InterruptedException, ExecutionException {
+        DOMDataReadWriteTransaction tx = txChain.newReadWriteTransaction();
+
+        /**
+         * We test existence of /test in third transaction container should
+         * still be visible from first one (which is still uncommmited).
+         *
+         */
+        assertTestContainerExists(tx);
+
+        /**
+         * We delete node in third transaction
+         */
+        tx.delete(LogicalDatastoreType.OPERATIONAL, TestModel.TEST_PATH);
+        return tx;
+    }
+
+    private static DOMDataReadWriteTransaction allocateAndWrite(final DOMTransactionChain txChain)
+            throws InterruptedException, ExecutionException {
+        DOMDataReadWriteTransaction tx = txChain.newReadWriteTransaction();
+        assertTestContainerWrite(tx);
+        return tx;
+    }
+
+    private static void assertCommitSuccessful(final ListenableFuture<RpcResult<TransactionStatus>> future)
+            throws InterruptedException, ExecutionException {
+        RpcResult<TransactionStatus> rpcResult = future.get();
+        assertTrue(rpcResult.isSuccessful());
+        assertEquals(TransactionStatus.COMMITED, rpcResult.getResult());
+    }
+
+    private static void assertTestContainerExists(final DOMDataReadTransaction readTx) throws InterruptedException,
+            ExecutionException {
+        ListenableFuture<Optional<NormalizedNode<?, ?>>> readFuture = readTx.read(OPERATIONAL, TestModel.TEST_PATH);
+        Optional<NormalizedNode<?, ?>> readedData = readFuture.get();
+        assertTrue(readedData.isPresent());
+    }
+
+    private static void assertTestContainerWrite(final DOMDataReadWriteTransaction tx) throws InterruptedException,
+            ExecutionException {
+        tx.put(OPERATIONAL, TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME));
+        assertTestContainerExists(tx);
+    }
+}
index 020ff8fa5062d640830202ae84ba56d42cb017c8..9c61d47b1fb6add79ea8ad0a9e82b0dc799b3aab 100644 (file)
 module basic-module {
-  namespace "basic:module";  
-
-  prefix "basmod";
-  
-  import referenced-module {prefix refmo; revision-date 2013-12-2;}
-   
-  revision 2013-12-2 {    
-  }
-  
-       container cont {
-          container cont1 {
-               leaf lf11 {
-                       type identityref {
-                               base "refmo:iden";
-                       }
-               }
-               }
-               leaf lfStr {
-                 type string;
-               }
-               leaf lfInt8 {
-                 type int8;
-               }
-               
-               leaf lfInt16 {
-                 type int16;
-               }
-               
-               leaf lfInt32 {
-                 type int32;
-               }
-               
-               leaf lfInt64 {
-                 type int64;
-               }
-               
-               leaf lfUint8 {
-                 type uint8;
-               }
-               
-               leaf lfUint16 {
-                 type uint16;
-               }
-               
-               leaf lfUint32 {
-                 type uint32;
-               }
-               
-               leaf lfUint64 {
-                 type uint64;
-               }
-               
-               leaf lfBinary {
-                 type binary;
-               }
-               
-               leaf lfBits {
-                 type bits {
-                     bit one;
-                     bit two;
-                     bit three;
-                 }
-               }
-               
-               leaf lfEnumeration {
-                 type enumeration {
-                     enum enum1;
-                     enum enum2;
-                     enum enum3;
-                 }
-               }
-               
-               leaf lfEmpty {
-                 type empty;
-               }
-               
-               leaf lfBoolean {
-                 type boolean;
-               }
-               
-               leaf lfUnion {
-                 type union {
-                     type int8;
-                     type string;
-                     type bits {
-                         bit first;
-                         bit second;
-                     }
-                     type boolean;
-                 }
-               }
-               
-               leaf lfLfref {
-                 type leafref {
-                     path "/cont/lfBoolean";
-                 }    
-               }
-               
-               leaf lfInIdentifier {
-                 type instance-identifier;
-               }
-               
-       }
-         
-}
\ No newline at end of file
+    namespace "basic:module";
+
+    prefix "basmod";
+
+    import referenced-module {prefix refmo; revision-date 2013-12-2;}
+
+    revision 2013-12-2 {
+    }
+
+    container cont {
+        container cont1 {
+            leaf lf11 {
+                type identityref {
+                    base "refmo:iden";
+                }
+            }
+        }
+        leaf lfStr {
+            type string;
+        }
+        leaf lfInt8 {
+            type int8;
+        }
+
+        leaf lfInt16 {
+            type int16;
+        }
+
+        leaf lfInt32 {
+            type int32;
+        }
+
+        leaf lfInt64 {
+            type int64;
+        }
+
+        leaf lfUint8 {
+            type uint8;
+        }
+
+        leaf lfUint16 {
+            type uint16;
+        }
+
+        leaf lfUint32 {
+            type uint32;
+        }
+
+        leaf lfUint64 {
+            type uint64;
+        }
+
+        leaf lfBinary {
+            type binary;
+        }
+
+        leaf lfBits {
+            type bits {
+                bit one;
+                bit two;
+                bit three;
+            }
+        }
+
+        leaf lfEnumeration {
+            type enumeration {
+                enum enum1;
+                enum enum2;
+                enum enum3;
+            }
+        }
+
+        leaf lfEmpty {
+            type empty;
+        }
+
+        leaf lfBoolean {
+            type boolean;
+        }
+
+        leaf lfUnion {
+            type union {
+                type int8;
+                type string;
+                type bits {
+                    bit first;
+                    bit second;
+                }
+                type boolean;
+            }
+        }
+
+        leaf lfLfref {
+            type leafref {
+                path "/cont/lfBoolean";
+            }
+        }
+
+        leaf lfInIdentifier {
+            type instance-identifier;
+        }
+
+    }
+
+}
diff --git a/pom.xml b/pom.xml
index 8ad038763c8f2909ff95974b888c281adbcf44ae..a26533819c45e8a8a89d696eef00093551db1b49 100644 (file)
--- a/pom.xml
+++ b/pom.xml
@@ -32,6 +32,7 @@
     <module>opendaylight/hosttracker_new/implementation</module>
     <module>opendaylight/containermanager/api</module>
     <module>opendaylight/containermanager/implementation</module>
+    <module>opendaylight/containermanager/shell</module>
     <module>opendaylight/appauth</module>
     <module>opendaylight/switchmanager/api</module>
     <module>opendaylight/switchmanager/implementation</module>
 
     <!-- Karaf Distribution -->
     <module>features/base</module>
+    <module>features/controller</module>
     <module>opendaylight/dummy-console</module>
     <module>opendaylight/karaf-branding</module>
     <module>opendaylight/distribution/opendaylight-karaf</module>