Merge "Bug 716: Errors on controller shutdown"
authorTony Tkacik <ttkacik@cisco.com>
Fri, 23 May 2014 12:42:54 +0000 (12:42 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Fri, 23 May 2014 12:42:54 +0000 (12:42 +0000)
36 files changed:
opendaylight/commons/opendaylight/pom.xml
opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/mapping/CodecRegistryProvider.java
opendaylight/distribution/opendaylight-karaf/pom.xml
opendaylight/distribution/opendaylight/pom.xml
opendaylight/dummy-console/pom.xml
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/ResolveDataChangeEventsTask.java
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/DataTreeCandidate.java
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/DataTreeCandidateNode.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/ModificationType.java [moved from opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/ModificationType.java with 91% similarity]
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/AbstractDataTreeCandidate.java
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/DataNodeContainerModificationStrategy.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/InMemoryDataTreeCandidate.java
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/InMemoryDataTreeModification.java
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/NodeModification.java
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/NoopDataTreeCandidate.java
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/NormalizedNodeContainerModificationStrategy.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/SchemaAwareApplyOperation.java
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/StoreMetadataNode.java
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/StoreNodeCompositeBuilder.java
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/ValueNodeModificationStrategy.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-broker/src/test/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/SchemaAwareApplyOperationRoot.java
opendaylight/md-sal/sal-rest-connector/pom.xml
opendaylight/md-sal/sal-rest-docgen/pom.xml
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/fromxml/SimpleAttributeReadingStrategy.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/toxml/ObjectNameAttributeWritingStrategy.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/toxml/SimpleIdentityRefAttributeWritingStrategy.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/ModuleConfig.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/Services.java
opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/NetconfMappingTest.java
opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/NetconfITTest.java
opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/xml/XmlElement.java
opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/xml/XmlUtil.java
opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronPortsNorthbound.java

index 7cec465..e1e3164 100644 (file)
@@ -17,9 +17,9 @@
   <properties>
     <aopalliance.version>1.0.0</aopalliance.version>
     <appauth.version>0.4.2-SNAPSHOT</appauth.version>
+    <aries.util.version>1.1.0</aries.util.version>
     <!-- Controller Modules Versions -->
     <arphandler.version>0.5.2-SNAPSHOT</arphandler.version>
-    <aries.util.version>1.1.0</aries.util.version>
     <asm.version>4.1</asm.version>
     <!-- Plugin Versions -->
     <bouncycastle.version>1.50</bouncycastle.version>
@@ -78,6 +78,7 @@
     <hosttracker.northbound.version>0.4.2-SNAPSHOT</hosttracker.northbound.version>
     <hosttracker_new.api.version>0.4.2-SNAPSHOT</hosttracker_new.api.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>
     <ietf-yang-types.version>2010.09.24.4-SNAPSHOT</ietf-yang-types.version>
     <jackson.version>2.3.2</jackson.version>
         <artifactId>netconf-netty-util</artifactId>
         <version>${netconf.version}</version>
       </dependency>
-      <dependency>
-        <groupId>org.opendaylight.controller</groupId>
-        <artifactId>netconf-netty-util</artifactId>
-        <version>${netconf.version}</version>
-        <type>test-jar</type>
-      </dependency>
       <dependency>
         <groupId>ch.qos.logback</groupId>
         <artifactId>logback-classic</artifactId>
         <artifactId>netconf-monitoring</artifactId>
         <version>${netconf.version}</version>
       </dependency>
+      <dependency>
+        <groupId>org.opendaylight.controller</groupId>
+        <artifactId>netconf-netty-util</artifactId>
+        <version>${netconf.version}</version>
+        <type>test-jar</type>
+      </dependency>
       <dependency>
         <groupId>org.opendaylight.controller</groupId>
         <artifactId>netconf-ssh</artifactId>
         <artifactId>ietf-inet-types</artifactId>
         <version>${ietf-inet-types.version}</version>
       </dependency>
+      <dependency>
+        <groupId>org.opendaylight.yangtools.model</groupId>
+        <artifactId>ietf-restconf</artifactId>
+        <version>${ietf-restconf.version}</version>
+      </dependency>
       <dependency>
         <groupId>org.opendaylight.yangtools.model</groupId>
         <artifactId>ietf-topology</artifactId>
         <artifactId>ietf-yang-types</artifactId>
         <version>${ietf-yang-types.version}</version>
       </dependency>
+      <dependency>
+        <groupId>org.opendaylight.yangtools.model</groupId>
+        <artifactId>ietf-yang-types-20130715</artifactId>
+        <version>2013.07.15.1-SNAPSHOT</version>
+      </dependency>
       <dependency>
         <groupId>org.opendaylight.yangtools.model</groupId>
         <artifactId>opendaylight-l2-types</artifactId>
index 9d0fbd8..ec46219 100644 (file)
@@ -8,6 +8,7 @@
 package org.opendaylight.controller.config.manager.impl.osgi.mapping;
 
 import javassist.ClassPool;
+
 import org.opendaylight.controller.config.manager.impl.util.OsgiRegistrationUtil;
 import org.opendaylight.yangtools.sal.binding.generator.api.ClassLoadingStrategy;
 import org.opendaylight.yangtools.sal.binding.generator.impl.RuntimeGeneratedMappingServiceImpl;
@@ -27,10 +28,8 @@ public class CodecRegistryProvider implements AutoCloseable {
     private final RuntimeGeneratedMappingServiceImpl service;
     private final AutoCloseable registration;
 
-    public CodecRegistryProvider(ClassLoadingStrategy classLoadingStrategy, BundleContext context) {
-        service = new RuntimeGeneratedMappingServiceImpl(classLoadingStrategy);
-        service.setPool(CLASS_POOL);
-        service.init();
+    public CodecRegistryProvider(final ClassLoadingStrategy classLoadingStrategy, final BundleContext context) {
+        service = new RuntimeGeneratedMappingServiceImpl(CLASS_POOL, classLoadingStrategy);
         registration = OsgiRegistrationUtil.registerService(context, service,
                 SchemaServiceListener.class, BindingIndependentMappingService.class);
     }
index 377785a..31cdedd 100644 (file)
       <version>${karaf.version}</version>
       <type>kar</type>
     </dependency>
-    <dependency>
-      <groupId>org.opendaylight.controller</groupId>
-      <artifactId>config-features</artifactId>
-      <version>${config.version}</version>
-      <classifier>features</classifier>
-      <type>xml</type>
-      <scope>runtime</scope>
-    </dependency>
     <!-- scope is runtime so the feature repo is listed in the features
       service config file, and features may be installed using the
       karaf-maven-plugin configuration -->
       <type>kar</type>
       <scope>runtime</scope>
     </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>config-features</artifactId>
+      <version>${config.version}</version>
+      <classifier>features</classifier>
+      <type>xml</type>
+      <scope>runtime</scope>
+    </dependency>
     <!--<dependency>
       <groupId>org.opendaylight.controller</groupId>
       <artifactId>base-features</artifactId>
index 48e661f..52aa6d2 100644 (file)
           <groupId>org.opendaylight.yangtools.model</groupId>
           <artifactId>ietf-inet-types</artifactId>
         </dependency>
+        <dependency>
+          <groupId>org.opendaylight.yangtools.model</groupId>
+          <artifactId>ietf-restconf</artifactId>
+        </dependency>
         <dependency>
           <groupId>org.opendaylight.yangtools.model</groupId>
           <artifactId>ietf-topology</artifactId>
           <groupId>org.opendaylight.yangtools.model</groupId>
           <artifactId>ietf-yang-types</artifactId>
         </dependency>
+        <dependency>
+          <groupId>org.opendaylight.yangtools.model</groupId>
+          <artifactId>ietf-yang-types-20130715</artifactId>
+        </dependency>
         <dependency>
           <groupId>org.opendaylight.yangtools.model</groupId>
           <artifactId>opendaylight-l2-types</artifactId>
index 6d90eb3..8901c2e 100644 (file)
@@ -16,7 +16,6 @@
       <plugin>
         <groupId>org.apache.felix</groupId>
         <artifactId>maven-bundle-plugin</artifactId>
-        <version>${bundle.plugin.version}</version>
         <extensions>true</extensions>
         <configuration>
           <instructions>
index 9e11fc7..00df658 100644 (file)
@@ -335,12 +335,8 @@ public class InMemoryDOMDataStore implements DOMStore, Identifiable<String>, Sch
 
         @Override
         public ListenableFuture<Void> abort() {
-            if (candidate != null) {
-                candidate.close();
-                candidate = null;
-            }
-
-            return Futures.<Void> immediateFuture(null);
+            candidate = null;
+            return Futures.immediateFuture(null);
         }
 
         @Override
@@ -360,7 +356,7 @@ public class InMemoryDOMDataStore implements DOMStore, Identifiable<String>, Sch
                 }
             }
 
-            return Futures.<Void> immediateFuture(null);
+            return Futures.immediateFuture(null);
         }
     }
 }
index db9bb0f..b36ef3d 100644 (file)
@@ -23,11 +23,11 @@ import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataCh
 import org.opendaylight.controller.md.sal.dom.store.impl.DOMImmutableDataChangeEvent.Builder;
 import org.opendaylight.controller.md.sal.dom.store.impl.DOMImmutableDataChangeEvent.SimpleEventFactory;
 import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataTreeCandidate;
+import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataTreeCandidateNode;
 import org.opendaylight.controller.md.sal.dom.store.impl.tree.ListenerTree;
 import org.opendaylight.controller.md.sal.dom.store.impl.tree.ListenerTree.Node;
 import org.opendaylight.controller.md.sal.dom.store.impl.tree.ListenerTree.Walker;
-import org.opendaylight.controller.md.sal.dom.store.impl.tree.data.NodeModification;
-import org.opendaylight.controller.md.sal.dom.store.impl.tree.data.StoreMetadataNode;
+import org.opendaylight.controller.md.sal.dom.store.impl.tree.ModificationType;
 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifier;
 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates;
@@ -73,9 +73,9 @@ final class ResolveDataChangeEventsTask implements Callable<Iterable<ChangeListe
     private final ListenerTree listenerRoot;
 
     public ResolveDataChangeEventsTask(DataTreeCandidate candidate, ListenerTree listenerTree) {
-       this.candidate = Preconditions.checkNotNull(candidate);
-       this.listenerRoot = Preconditions.checkNotNull(listenerTree);
-       }
+        this.candidate = Preconditions.checkNotNull(candidate);
+        this.listenerRoot = Preconditions.checkNotNull(listenerTree);
+    }
 
     /**
      * Resolves and creates Notification Tasks
@@ -89,9 +89,7 @@ final class ResolveDataChangeEventsTask implements Callable<Iterable<ChangeListe
     @Override
     public Iterable<ChangeListenerNotifyTask> call() {
         try (final Walker w = listenerRoot.getWalker()) {
-            resolveAnyChangeEvent(candidate.getRootPath(), Collections.singleton(w.getRootNode()),
-                       candidate.getModificationRoot(), Optional.fromNullable(candidate.getBeforeRoot()),
-                       Optional.fromNullable(candidate.getAfterRoot()));
+            resolveAnyChangeEvent(candidate.getRootPath(), Collections.singleton(w.getRootNode()), candidate.getRootNode());
             return createNotificationTasks();
         }
     }
@@ -256,29 +254,38 @@ final class ResolveDataChangeEventsTask implements Callable<Iterable<ChangeListe
      * @return Data Change Event of this node and all it's children
      */
     private DOMImmutableDataChangeEvent resolveAnyChangeEvent(final InstanceIdentifier path,
-            final Collection<ListenerTree.Node> listeners, final NodeModification modification,
-            final Optional<StoreMetadataNode> before, final Optional<StoreMetadataNode> after) {
-        // No listeners are present in listener registration subtree
-        // no before and after state is present
-        if (!before.isPresent() && !after.isPresent()) {
+            final Collection<ListenerTree.Node> listeners, final DataTreeCandidateNode node) {
+
+        if (node.getModificationType() != ModificationType.UNMODIFIED &&
+                !node.getDataAfter().isPresent() && !node.getDataBefore().isPresent()) {
+            LOG.debug("Modification at {} has type {}, but no before- and after-data. Assuming unchanged.",
+                    path, node.getModificationType());
             return NO_CHANGE;
         }
-        switch (modification.getModificationType()) {
+
+        // no before and after state is present
+
+        switch (node.getModificationType()) {
         case SUBTREE_MODIFIED:
-            return resolveSubtreeChangeEvent(path, listeners, modification, before.get(), after.get());
+            return resolveSubtreeChangeEvent(path, listeners, node);
         case MERGE:
         case WRITE:
-            if (before.isPresent()) {
-                return resolveReplacedEvent(path, listeners, before.get().getData(), after.get().getData());
+            Preconditions.checkArgument(node.getDataAfter().isPresent(),
+                    "Modification at {} has type {} but no after-data", path, node.getModificationType());
+            if (node.getDataBefore().isPresent()) {
+                return resolveReplacedEvent(path, listeners, node.getDataBefore().get(), node.getDataAfter().get());
             } else {
-                return resolveCreateEvent(path, listeners, after.get());
+                return resolveCreateEvent(path, listeners, node.getDataAfter().get());
             }
         case DELETE:
-            return resolveDeleteEvent(path, listeners, before.get());
-        default:
+            Preconditions.checkArgument(node.getDataBefore().isPresent(),
+                    "Modification at {} has type {} but no before-data", path, node.getModificationType());
+            return resolveDeleteEvent(path, listeners, node.getDataBefore().get());
+        case UNMODIFIED:
             return NO_CHANGE;
         }
 
+        throw new IllegalStateException(String.format("Unhandled node state %s at %s", node.getModificationType(), path));
     }
 
     private DOMImmutableDataChangeEvent resolveReplacedEvent(final InstanceIdentifier path,
@@ -313,7 +320,7 @@ final class ResolveDataChangeEventsTask implements Callable<Iterable<ChangeListe
     private DOMImmutableDataChangeEvent resolveNodeContainerReplaced(final InstanceIdentifier path,
             final Collection<Node> listeners,
             final NormalizedNodeContainer<?, PathArgument, NormalizedNode<PathArgument, ?>> beforeCont,
-            final NormalizedNodeContainer<?, PathArgument, NormalizedNode<PathArgument, ?>> afterCont) {
+                    final NormalizedNodeContainer<?, PathArgument, NormalizedNode<PathArgument, ?>> afterCont) {
         final Set<PathArgument> alreadyProcessed = new HashSet<>();
         final List<DOMImmutableDataChangeEvent> childChanges = new LinkedList<>();
 
@@ -388,17 +395,17 @@ final class ResolveDataChangeEventsTask implements Callable<Iterable<ChangeListe
      * @return
      */
     private DOMImmutableDataChangeEvent resolveCreateEvent(final InstanceIdentifier path,
-            final Collection<ListenerTree.Node> listeners, final StoreMetadataNode afterState) {
+            final Collection<ListenerTree.Node> listeners, final NormalizedNode<?, ?> afterState) {
         @SuppressWarnings({ "unchecked", "rawtypes" })
-        final NormalizedNode<PathArgument, ?> node = (NormalizedNode) afterState.getData();
+        final NormalizedNode<PathArgument, ?> node = (NormalizedNode) afterState;
         return resolveSameEventRecursivelly(path, listeners, node, DOMImmutableDataChangeEvent.getCreateEventFactory());
     }
 
     private DOMImmutableDataChangeEvent resolveDeleteEvent(final InstanceIdentifier path,
-            final Collection<ListenerTree.Node> listeners, final StoreMetadataNode beforeState) {
+            final Collection<ListenerTree.Node> listeners, final NormalizedNode<?, ?> beforeState) {
 
         @SuppressWarnings({ "unchecked", "rawtypes" })
-        final NormalizedNode<PathArgument, ?> node = (NormalizedNode) beforeState.getData();
+        final NormalizedNode<PathArgument, ?> node = (NormalizedNode) beforeState;
         return resolveSameEventRecursivelly(path, listeners, node, DOMImmutableDataChangeEvent.getRemoveEventFactory());
     }
 
@@ -408,7 +415,7 @@ final class ResolveDataChangeEventsTask implements Callable<Iterable<ChangeListe
         final DOMImmutableDataChangeEvent event = eventFactory.create(path, node);
         DOMImmutableDataChangeEvent propagateEvent = event;
         // We have listeners for this node or it's children, so we will try
-            // to do additional processing
+        // to do additional processing
         if (node instanceof NormalizedNodeContainer<?, ?, ?>) {
             LOG.trace("Resolving subtree recursive event for {}, type {}", path, eventFactory);
 
@@ -439,30 +446,31 @@ final class ResolveDataChangeEventsTask implements Callable<Iterable<ChangeListe
     }
 
     private DOMImmutableDataChangeEvent resolveSubtreeChangeEvent(final InstanceIdentifier path,
-            final Collection<ListenerTree.Node> listeners, final NodeModification modification,
-            final StoreMetadataNode before, final StoreMetadataNode after) {
+            final Collection<ListenerTree.Node> listeners, final DataTreeCandidateNode modification) {
 
-        Builder one = builder(DataChangeScope.ONE).setBefore(before.getData()).setAfter(after.getData());
+        Preconditions.checkArgument(modification.getDataBefore().isPresent(), "Subtree change with before-data not present at path %s", path);
+        Preconditions.checkArgument(modification.getDataAfter().isPresent(), "Subtree change with after-data not present at path %s", path);
 
-        Builder subtree = builder(DataChangeScope.SUBTREE).setBefore(before.getData()).setAfter(after.getData());
+        Builder one = builder(DataChangeScope.ONE).
+                setBefore(modification.getDataBefore().get()).
+                setAfter(modification.getDataAfter().get());
+        Builder subtree = builder(DataChangeScope.SUBTREE).
+                setBefore(modification.getDataBefore().get()).
+                setAfter(modification.getDataAfter().get());
 
-        for (NodeModification childMod : modification.getModifications()) {
+        for (DataTreeCandidateNode childMod : modification.getChildNodes()) {
             PathArgument childId = childMod.getIdentifier();
             InstanceIdentifier childPath = append(path, childId);
             Collection<ListenerTree.Node> childListeners = getListenerChildrenWildcarded(listeners, childId);
 
-            Optional<StoreMetadataNode> childBefore = before.getChild(childId);
-            Optional<StoreMetadataNode> childAfter = after.getChild(childId);
-
             switch (childMod.getModificationType()) {
             case WRITE:
             case MERGE:
             case DELETE:
-                one.merge(resolveAnyChangeEvent(childPath, childListeners, childMod, childBefore, childAfter));
+                one.merge(resolveAnyChangeEvent(childPath, childListeners, childMod));
                 break;
             case SUBTREE_MODIFIED:
-                subtree.merge(resolveSubtreeChangeEvent(childPath, childListeners, childMod, childBefore.get(),
-                        childAfter.get()));
+                subtree.merge(resolveSubtreeChangeEvent(childPath, childListeners, childMod));
                 break;
             case UNMODIFIED:
                 // no-op
@@ -514,7 +522,7 @@ final class ResolveDataChangeEventsTask implements Callable<Iterable<ChangeListe
         }
     }
 
-       public static ResolveDataChangeEventsTask create(DataTreeCandidate candidate, ListenerTree listenerTree) {
+    public static ResolveDataChangeEventsTask create(DataTreeCandidate candidate, ListenerTree listenerTree) {
         return new ResolveDataChangeEventsTask(candidate, listenerTree);
-       }
+    }
 }
index 01e2a29..ee9726a 100644 (file)
@@ -13,20 +13,20 @@ import org.opendaylight.yangtools.yang.model.api.SchemaContext;
  * Interface representing a data tree which can be modified in an MVCC fashion.
  */
 public interface DataTree {
-       /**
-        * Take a read-only point-in-time snapshot of the tree.
-        *
-        * @return Data tree snapshot.
-        */
-       DataTreeSnapshot takeSnapshot();
+    /**
+     * Take a read-only point-in-time snapshot of the tree.
+     *
+     * @return Data tree snapshot.
+     */
+    DataTreeSnapshot takeSnapshot();
 
-       /**
-        * Make the data tree use a new schema context. The context will be used
-        * only by subsequent operations.
-        *
-        * @param newSchemaContext new SchemaContext
-        * @throws IllegalArgumentException if the new context is incompatible
-        */
+    /**
+     * Make the data tree use a new schema context. The context will be used
+     * only by subsequent operations.
+     *
+     * @param newSchemaContext new SchemaContext
+     * @throws IllegalArgumentException if the new context is incompatible
+     */
     void setSchemaContext(SchemaContext newSchemaContext);
 
     /**
index 79ce37e..906e284 100644 (file)
@@ -7,22 +7,9 @@
  */
 package org.opendaylight.controller.md.sal.dom.store.impl.tree;
 
-import org.opendaylight.controller.md.sal.dom.store.impl.tree.data.NodeModification;
-import org.opendaylight.controller.md.sal.dom.store.impl.tree.data.StoreMetadataNode;
 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
 
-public interface DataTreeCandidate extends AutoCloseable {
-       @Override
-       void close();
-
-       InstanceIdentifier getRootPath();
-
-       @Deprecated
-       NodeModification getModificationRoot();
-
-       @Deprecated
-       StoreMetadataNode getBeforeRoot();
-
-       @Deprecated
-       StoreMetadataNode getAfterRoot();
+public interface DataTreeCandidate {
+    DataTreeCandidateNode getRootNode();
+    InstanceIdentifier getRootPath();
 }
diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/DataTreeCandidateNode.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/DataTreeCandidateNode.java
new file mode 100644 (file)
index 0000000..b1ca45b
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * 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.PathArgument;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+import com.google.common.base.Optional;
+
+public interface DataTreeCandidateNode {
+    PathArgument getIdentifier();
+    Iterable<DataTreeCandidateNode> getChildNodes();
+
+    ModificationType getModificationType();
+    Optional<NormalizedNode<?, ?>> getDataAfter();
+    Optional<NormalizedNode<?, ?>> getDataBefore();
+}
index b2faf79..cddda5c 100644 (file)
@@ -13,21 +13,15 @@ import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
 import com.google.common.base.Preconditions;
 
 abstract class AbstractDataTreeCandidate implements DataTreeCandidate {
-       private final InstanceIdentifier rootPath;
-       private final NodeModification modificationRoot;
+    private final InstanceIdentifier rootPath;
 
-       protected AbstractDataTreeCandidate(final InstanceIdentifier rootPath, NodeModification modificationRoot) {
-               this.rootPath = Preconditions.checkNotNull(rootPath);
-               this.modificationRoot = Preconditions.checkNotNull(modificationRoot);
-       }
+    protected AbstractDataTreeCandidate(final InstanceIdentifier rootPath) {
+        this.rootPath = Preconditions.checkNotNull(rootPath);
+    }
 
-       @Override
-       public final InstanceIdentifier getRootPath() {
-               return rootPath;
-       }
+    @Override
+    public final InstanceIdentifier getRootPath() {
+        return rootPath;
+    }
 
-       @Override
-       public final NodeModification getModificationRoot() {
-               return modificationRoot;
-       }
 }
diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/DataNodeContainerModificationStrategy.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/DataNodeContainerModificationStrategy.java
new file mode 100644 (file)
index 0000000..aea070c
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * 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.data;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+import java.util.HashSet;
+import java.util.Set;
+import java.util.concurrent.ExecutionException;
+
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.AugmentationIdentifier;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListEntryNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableAugmentationNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableContainerNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableMapEntryNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableUnkeyedListEntryNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.transform.base.AugmentationSchemaProxy;
+import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
+import org.opendaylight.yangtools.yang.model.api.AugmentationTarget;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
+
+abstract class DataNodeContainerModificationStrategy<T extends DataNodeContainer> extends NormalizedNodeContainerModificationStrategy {
+
+    private final T schema;
+    private final LoadingCache<PathArgument, ModificationApplyOperation> childCache = CacheBuilder.newBuilder()
+            .build(CacheLoader.from(new Function<PathArgument, ModificationApplyOperation>() {
+
+                @Override
+                public ModificationApplyOperation apply(final PathArgument identifier) {
+                    if (identifier instanceof AugmentationIdentifier && schema instanceof AugmentationTarget) {
+                        return from(schema, (AugmentationTarget) schema, (AugmentationIdentifier) identifier);
+                    }
+
+                    DataSchemaNode child = schema.getDataChildByName(identifier.getNodeType());
+                    if (child == null) {
+                        return null;
+                    }
+                    return from(child);
+                }
+            }));
+
+    protected DataNodeContainerModificationStrategy(final T schema,
+            final Class<? extends NormalizedNode<?, ?>> nodeClass) {
+        super(nodeClass);
+        this.schema = schema;
+    }
+
+    protected T getSchema() {
+        return schema;
+    }
+
+    @Override
+    public Optional<ModificationApplyOperation> getChild(final PathArgument identifier) {
+        try {
+            return Optional.<ModificationApplyOperation> fromNullable(childCache.get(identifier));
+        } catch (ExecutionException e) {
+            return Optional.absent();
+        }
+    }
+
+    @Override
+    @SuppressWarnings("rawtypes")
+    protected abstract DataContainerNodeBuilder createBuilder(NormalizedNode<?, ?> original);
+
+    @Override
+    public String toString() {
+        return getClass().getSimpleName() + " [" + schema + "]";
+    }
+
+    public static class AugmentationModificationStrategy extends DataNodeContainerModificationStrategy<AugmentationSchema> {
+
+        protected AugmentationModificationStrategy(final AugmentationSchema schema, final DataNodeContainer resolved) {
+            super(createAugmentProxy(schema,resolved), AugmentationNode.class);
+        }
+
+        @Override
+        @SuppressWarnings("rawtypes")
+        protected DataContainerNodeBuilder createBuilder(final NormalizedNode<?, ?> original) {
+            checkArgument(original instanceof AugmentationNode);
+            return ImmutableAugmentationNodeBuilder.create((AugmentationNode) original);
+        }
+
+
+        private static AugmentationSchema createAugmentProxy(final AugmentationSchema schema, final DataNodeContainer resolved) {
+            Set<DataSchemaNode> realChildSchemas = new HashSet<>();
+            for(DataSchemaNode augChild : schema.getChildNodes()) {
+                realChildSchemas.add(resolved.getDataChildByName(augChild.getQName()));
+            }
+            return new AugmentationSchemaProxy(schema, realChildSchemas);
+        }
+    }
+
+    public static class ContainerModificationStrategy extends DataNodeContainerModificationStrategy<ContainerSchemaNode> {
+
+        public ContainerModificationStrategy(final ContainerSchemaNode schemaNode) {
+            super(schemaNode, ContainerNode.class);
+        }
+
+        @Override
+        @SuppressWarnings("rawtypes")
+        protected DataContainerNodeBuilder createBuilder(final NormalizedNode<?, ?> original) {
+            checkArgument(original instanceof ContainerNode);
+            return ImmutableContainerNodeBuilder.create((ContainerNode) original);
+        }
+    }
+
+    public static class ListEntryModificationStrategy extends DataNodeContainerModificationStrategy<ListSchemaNode> {
+
+        protected ListEntryModificationStrategy(final ListSchemaNode schema) {
+            super(schema, MapEntryNode.class);
+        }
+
+        @Override
+        @SuppressWarnings("rawtypes")
+        protected final DataContainerNodeBuilder createBuilder(final NormalizedNode<?, ?> original) {
+            checkArgument(original instanceof MapEntryNode);
+            return ImmutableMapEntryNodeBuilder.create((MapEntryNode) original);
+        }
+    }
+
+    public static class UnkeyedListItemModificationStrategy extends DataNodeContainerModificationStrategy<ListSchemaNode> {
+
+        public UnkeyedListItemModificationStrategy(final ListSchemaNode schemaNode) {
+            super(schemaNode, UnkeyedListEntryNode.class);
+        }
+
+        @Override
+        @SuppressWarnings("rawtypes")
+        protected DataContainerNodeBuilder createBuilder(final NormalizedNode<?, ?> original) {
+            checkArgument(original instanceof UnkeyedListEntryNode);
+            return ImmutableUnkeyedListEntryNodeBuilder.create((UnkeyedListEntryNode) original);
+        }
+    }
+}
\ No newline at end of file
index 5a300a0..f04e379 100644 (file)
@@ -14,6 +14,7 @@ import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataPreconditionFa
 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.ModificationType;
 import org.opendaylight.controller.md.sal.dom.store.impl.tree.StoreUtils;
 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
@@ -127,7 +128,7 @@ final class InMemoryDataTree implements DataTree {
         rwLock.writeLock().lock();
         try {
             Preconditions.checkState(c.getBeforeRoot() == rootNode,
-                    String.format("Store snapshot %s and transaction snapshot %s differ.", rootNode, c.getBeforeRoot()));
+                    String.format("Store tree %s and candidate base %s differ.", rootNode, c.getBeforeRoot()));
             this.rootNode = c.getAfterRoot();
         } finally {
             rwLock.writeLock().unlock();
index 93719b7..72562f0 100644 (file)
 package org.opendaylight.controller.md.sal.dom.store.impl.tree.data;
 
+import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataTreeCandidateNode;
+import org.opendaylight.controller.md.sal.dom.store.impl.tree.ModificationType;
 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
 
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
+import com.google.common.collect.Iterables;
 
 final class InMemoryDataTreeCandidate extends AbstractDataTreeCandidate {
-       private final StoreMetadataNode newRoot;
-       private final StoreMetadataNode oldRoot;
-
-       InMemoryDataTreeCandidate(final InstanceIdentifier rootPath, final NodeModification modificationRoot,
-                       final StoreMetadataNode oldRoot, final StoreMetadataNode newRoot) {
-               super(rootPath, modificationRoot);
-               this.newRoot = Preconditions.checkNotNull(newRoot);
-               this.oldRoot = Preconditions.checkNotNull(oldRoot);
-       }
-
-       @Override
-       public void close() {
-               // FIXME: abort operation here :)
-       }
-
-       @Override
-       public StoreMetadataNode getBeforeRoot() {
-               return oldRoot;
-       }
-
-       @Override
-       public StoreMetadataNode getAfterRoot() {
-               return newRoot;
-       }
+    private static abstract class AbstractNode implements DataTreeCandidateNode {
+        private final StoreMetadataNode newMeta;
+        private final StoreMetadataNode oldMeta;
+        private final NodeModification mod;
+
+        protected AbstractNode(final NodeModification mod,
+                final StoreMetadataNode oldMeta, final StoreMetadataNode newMeta) {
+            this.newMeta = newMeta;
+            this.oldMeta = oldMeta;
+            this.mod = Preconditions.checkNotNull(mod);
+        }
+
+        protected final NodeModification getMod() {
+            return mod;
+        }
+
+        protected final StoreMetadataNode getNewMeta() {
+            return newMeta;
+        }
+
+        protected final StoreMetadataNode getOldMeta() {
+            return oldMeta;
+        }
+
+        private static final StoreMetadataNode childMeta(final StoreMetadataNode parent, final PathArgument id) {
+            return parent == null ? null : parent.getChild(id).orNull();
+        }
+
+        @Override
+        public Iterable<DataTreeCandidateNode> getChildNodes() {
+            return Iterables.transform(mod.getModifications(), new Function<NodeModification, DataTreeCandidateNode>() {
+                @Override
+                public DataTreeCandidateNode apply(final NodeModification input) {
+                    final PathArgument id = input.getIdentifier();
+                    return new ChildNode(input, childMeta(oldMeta, id), childMeta(newMeta, id));
+                }
+            });
+        }
+
+        @Override
+        public ModificationType getModificationType() {
+            return mod.getModificationType();
+        }
+
+        private Optional<NormalizedNode<?, ?>> optionalData(StoreMetadataNode meta) {
+            if (meta == null) {
+                return Optional.absent();
+            }
+            return Optional.<NormalizedNode<?,?>>of(meta.getData());
+        }
+
+        @Override
+        public Optional<NormalizedNode<?, ?>> getDataAfter() {
+            return optionalData(newMeta);
+        }
+
+        @Override
+        public Optional<NormalizedNode<?, ?>> getDataBefore() {
+            return optionalData(oldMeta);
+        }
+    }
+
+    private static final class ChildNode extends AbstractNode {
+        public ChildNode(NodeModification mod, StoreMetadataNode oldMeta, StoreMetadataNode newMeta) {
+            super(mod, oldMeta, newMeta);
+        }
+
+        @Override
+        public PathArgument getIdentifier() {
+            return getMod().getIdentifier();
+        }
+    }
+
+    private static final class RootNode extends AbstractNode {
+        public RootNode(NodeModification mod, StoreMetadataNode oldMeta, StoreMetadataNode newMeta) {
+            super(mod, oldMeta, newMeta);
+        }
+
+        @Override
+        public PathArgument getIdentifier() {
+            throw new IllegalStateException("Attempted to get identifier of the root node");
+        }
+    }
+
+    private final RootNode root;
+
+    InMemoryDataTreeCandidate(final InstanceIdentifier rootPath, final NodeModification modificationRoot,
+            final StoreMetadataNode oldRoot, final StoreMetadataNode newRoot) {
+        super(rootPath);
+        this.root = new RootNode(modificationRoot, oldRoot, newRoot);
+    }
+
+    StoreMetadataNode getAfterRoot() {
+        return root.getNewMeta();
+    }
+
+    StoreMetadataNode getBeforeRoot() {
+        return root.getOldMeta();
+    }
+
+    @Override
+    public DataTreeCandidateNode getRootNode() {
+        return root;
+    }
 }
index df3ef8b..7d0c81e 100644 (file)
@@ -88,30 +88,32 @@ final class InMemoryDataTreeModification implements DataTreeModification {
 
     @Override
     public Optional<NormalizedNode<?, ?>> readNode(final InstanceIdentifier path) {
-        Entry<InstanceIdentifier, NodeModification> modification = TreeNodeUtils.findClosestsOrFirstMatch(rootNode, path, NodeModification.IS_TERMINAL_PREDICATE);
-
-        Optional<StoreMetadataNode> result = resolveSnapshot(modification);
+        /*
+         * Walk the tree from the top, looking for the first node between root and
+         * the requested path which has been modified. If no such node exists,
+         * we use the node itself.
+         */
+        final Entry<InstanceIdentifier, NodeModification> entry = TreeNodeUtils.findClosestsOrFirstMatch(rootNode, path, NodeModification.IS_TERMINAL_PREDICATE);
+        final InstanceIdentifier key = entry.getKey();
+        final NodeModification mod = entry.getValue();
+
+        final Optional<StoreMetadataNode> result = resolveSnapshot(key, mod);
         if (result.isPresent()) {
             NormalizedNode<?, ?> data = result.get().getData();
-            return NormalizedNodeUtils.findNode(modification.getKey(), data, path);
+            return NormalizedNodeUtils.findNode(key, data, path);
+        } else {
+            return Optional.absent();
         }
-        return Optional.absent();
-    }
-
-    private Optional<StoreMetadataNode> resolveSnapshot(
-            final Entry<InstanceIdentifier, NodeModification> keyModification) {
-        InstanceIdentifier path = keyModification.getKey();
-        NodeModification modification = keyModification.getValue();
-        return resolveSnapshot(path, modification);
     }
 
     private Optional<StoreMetadataNode> resolveSnapshot(final InstanceIdentifier path,
             final NodeModification modification) {
+        final Optional<Optional<StoreMetadataNode>> potentialSnapshot = modification.getSnapshotCache();
+        if(potentialSnapshot.isPresent()) {
+            return potentialSnapshot.get();
+        }
+
         try {
-            Optional<Optional<StoreMetadataNode>> potentialSnapshot = modification.getSnapshotCache();
-            if(potentialSnapshot.isPresent()) {
-                return potentialSnapshot.get();
-            }
             return resolveModificationStrategy(path).apply(modification, modification.getOriginal(),
                     StoreUtils.increase(snapshot.getRootNode().getSubtreeVersion()));
         } catch (Exception e) {
index 18179af..f2720b5 100644 (file)
@@ -14,6 +14,7 @@ import java.util.Map;
 
 import javax.annotation.concurrent.GuardedBy;
 
+import org.opendaylight.controller.md.sal.dom.store.impl.tree.ModificationType;
 import org.opendaylight.controller.md.sal.dom.store.impl.tree.StoreTreeNode;
 import org.opendaylight.yangtools.concepts.Identifiable;
 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
@@ -30,10 +31,8 @@ import com.google.common.base.Predicate;
  *
  * This tree is lazily created and populated via {@link #modifyChild(PathArgument)}
  * and {@link StoreMetadataNode} which represents original state {@link #getOriginal()}.
- *
  */
-// FIXME: hide this class
-public class NodeModification implements StoreTreeNode<NodeModification>, Identifiable<PathArgument> {
+final class NodeModification implements StoreTreeNode<NodeModification>, Identifiable<PathArgument> {
 
     public static final Predicate<NodeModification> IS_TERMINAL_PREDICATE = new Predicate<NodeModification>() {
         @Override
index 1782da2..8a46748 100644 (file)
@@ -7,25 +7,52 @@
  */
 package org.opendaylight.controller.md.sal.dom.store.impl.tree.data;
 
+import java.util.Collections;
+
+import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataTreeCandidateNode;
+import org.opendaylight.controller.md.sal.dom.store.impl.tree.ModificationType;
 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
 
 final class NoopDataTreeCandidate extends AbstractDataTreeCandidate {
-       protected NoopDataTreeCandidate(final InstanceIdentifier rootPath, final NodeModification modificationRoot) {
-               super(rootPath, modificationRoot);
-       }
-
-       @Override
-       public void close() {
-               // NO-OP
-       }
-
-       @Override
-       public StoreMetadataNode getBeforeRoot() {
-               return null;
-       }
-
-       @Override
-       public StoreMetadataNode getAfterRoot() {
-               return null;
-       }
+    private static final DataTreeCandidateNode ROOT = new DataTreeCandidateNode() {
+        @Override
+        public ModificationType getModificationType() {
+            return ModificationType.UNMODIFIED;
+        }
+
+        @Override
+        public Iterable<DataTreeCandidateNode> getChildNodes() {
+            return Collections.emptyList();
+        }
+
+        @Override
+        public PathArgument getIdentifier() {
+            throw new IllegalStateException("Attempted to read identifier of the no-operation change");
+        }
+
+        @Override
+        public Optional<NormalizedNode<?, ?>> getDataAfter() {
+            return Optional.absent();
+        }
+
+        @Override
+        public Optional<NormalizedNode<?, ?>> getDataBefore() {
+            return Optional.absent();
+        }
+    };
+
+    protected NoopDataTreeCandidate(final InstanceIdentifier rootPath, final NodeModification modificationRoot) {
+        super(rootPath);
+        Preconditions.checkArgument(modificationRoot.getModificationType() == ModificationType.UNMODIFIED);
+    }
+
+    @Override
+    public DataTreeCandidateNode getRootNode() {
+        return ROOT;
+    }
 }
diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/NormalizedNodeContainerModificationStrategy.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/NormalizedNodeContainerModificationStrategy.java
new file mode 100644 (file)
index 0000000..7ab840e
--- /dev/null
@@ -0,0 +1,328 @@
+/*
+ * 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.data;
+
+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.ModificationType;
+import org.opendaylight.controller.md.sal.dom.store.impl.tree.StoreUtils;
+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;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeWithValue;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodeContainer;
+import org.opendaylight.yangtools.yang.data.api.schema.OrderedLeafSetNode;
+import org.opendaylight.yangtools.yang.data.api.schema.OrderedMapNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeContainerBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableChoiceNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableLeafSetNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableMapNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableOrderedLeafSetNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableOrderedMapNodeBuilder;
+import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
+import org.opendaylight.yangtools.yang.model.api.ChoiceNode;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+
+import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.primitives.UnsignedLong;
+
+abstract class NormalizedNodeContainerModificationStrategy extends SchemaAwareApplyOperation {
+
+    private final Class<? extends NormalizedNode<?, ?>> nodeClass;
+
+    protected NormalizedNodeContainerModificationStrategy(final Class<? extends NormalizedNode<?, ?>> nodeClass) {
+        this.nodeClass = nodeClass;
+    }
+
+    @Override
+    public void verifyStructure(final NodeModification modification) throws IllegalArgumentException {
+        if (modification.getModificationType() == ModificationType.WRITE) {
+
+        }
+        for (NodeModification childModification : modification.getModifications()) {
+            resolveChildOperation(childModification.getIdentifier()).verifyStructure(childModification);
+        }
+    }
+
+    @Override
+    protected void checkWriteApplicable(final InstanceIdentifier path, final NodeModification modification,
+            final Optional<StoreMetadataNode> current) throws DataPreconditionFailedException {
+        // 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.
+    }
+
+    @SuppressWarnings("rawtypes")
+    @Override
+    protected void verifyWrittenStructure(final NormalizedNode<?, ?> writtenValue) {
+        checkArgument(nodeClass.isInstance(writtenValue), "Node should must be of type %s", nodeClass);
+        checkArgument(writtenValue instanceof NormalizedNodeContainer);
+
+        NormalizedNodeContainer container = (NormalizedNodeContainer) writtenValue;
+        for (Object child : container.getValue()) {
+            checkArgument(child instanceof NormalizedNode);
+
+            /*
+             * FIXME: fail-fast semantics:
+             *
+             * We can validate the data structure here, aborting the commit
+             * before it ever progresses to being committed.
+             */
+        }
+    }
+
+    @Override
+    protected StoreMetadataNode applyWrite(final NodeModification modification,
+            final Optional<StoreMetadataNode> currentMeta, final UnsignedLong subtreeVersion) {
+
+        NormalizedNode<?, ?> newValue = modification.getWrittenValue();
+
+        final UnsignedLong nodeVersion;
+        if (currentMeta.isPresent()) {
+            nodeVersion = StoreUtils.increase(currentMeta.get().getNodeVersion());
+        } else {
+            nodeVersion = subtreeVersion;
+        }
+
+        final StoreMetadataNode newValueMeta = StoreMetadataNode.createRecursively(newValue, nodeVersion);
+        if (!modification.hasAdditionalModifications()) {
+            return newValueMeta;
+        }
+
+        @SuppressWarnings("rawtypes")
+        NormalizedNodeContainerBuilder dataBuilder = createBuilder(newValue);
+        StoreNodeCompositeBuilder builder = StoreNodeCompositeBuilder.create(nodeVersion, dataBuilder) //
+                .setSubtreeVersion(subtreeVersion);
+
+        return mutateChildren(modification.getModifications(), newValueMeta, builder, nodeVersion);
+    }
+
+    @Override
+    protected StoreMetadataNode applyMerge(final NodeModification modification, final StoreMetadataNode currentMeta,
+            final UnsignedLong subtreeVersion) {
+        // For Node Containers - merge is same as subtree change - we only replace children.
+        return applySubtreeChange(modification, currentMeta, subtreeVersion);
+    }
+
+    @Override
+    public StoreMetadataNode applySubtreeChange(final NodeModification modification,
+            final StoreMetadataNode currentMeta, final UnsignedLong subtreeVersion) {
+        // Bump subtree version to its new target
+        final UnsignedLong updatedSubtreeVersion = StoreUtils.increase(currentMeta.getSubtreeVersion());
+
+        @SuppressWarnings("rawtypes")
+        NormalizedNodeContainerBuilder dataBuilder = createBuilder(currentMeta.getData());
+        StoreNodeCompositeBuilder builder = StoreNodeCompositeBuilder.create(dataBuilder, currentMeta)
+                .setIdentifier(modification.getIdentifier())
+                .setSubtreeVersion(updatedSubtreeVersion);
+
+        return mutateChildren(modification.getModifications(), currentMeta, builder, updatedSubtreeVersion);
+    }
+
+    private StoreMetadataNode mutateChildren(final Iterable<NodeModification> modifications, final StoreMetadataNode meta,
+            final StoreNodeCompositeBuilder builder, final UnsignedLong nodeVersion) {
+
+        for (NodeModification mod : modifications) {
+            final PathArgument id = mod.getIdentifier();
+            final Optional<StoreMetadataNode> cm = meta.getChild(id);
+
+            Optional<StoreMetadataNode> result = resolveChildOperation(id).apply(mod, cm, nodeVersion);
+            if (result.isPresent()) {
+                builder.add(result.get());
+            } else {
+                builder.remove(id);
+            }
+        }
+
+        return builder.build();
+    }
+
+    @Override
+    protected void checkSubtreeModificationApplicable(final InstanceIdentifier path,final NodeModification modification,
+            final Optional<StoreMetadataNode> current) throws DataPreconditionFailedException {
+        checkDataPrecondition(path, current.isPresent(), "Node was deleted by other transaction.");
+        checkChildPreconditions(path,modification,current);
+
+    }
+
+    private void checkChildPreconditions(final InstanceIdentifier path, final NodeModification modification, final Optional<StoreMetadataNode> current) throws DataPreconditionFailedException {
+        StoreMetadataNode currentMeta = current.get();
+        for (NodeModification childMod : modification.getModifications()) {
+            PathArgument childId = childMod.getIdentifier();
+            Optional<StoreMetadataNode> childMeta = currentMeta.getChild(childId);
+            InstanceIdentifier childPath = StoreUtils.append(path, childId);
+            resolveChildOperation(childId).checkApplicable(childPath,childMod, childMeta);
+        }
+    }
+
+    @Override
+    protected void checkMergeApplicable(final InstanceIdentifier path, final NodeModification modification,
+            final Optional<StoreMetadataNode> current) throws DataPreconditionFailedException {
+        if(current.isPresent()) {
+            checkChildPreconditions(path,modification,current);
+        }
+    }
+
+    @SuppressWarnings("rawtypes")
+    protected abstract NormalizedNodeContainerBuilder createBuilder(NormalizedNode<?, ?> original);
+
+    public static class ChoiceModificationStrategy extends NormalizedNodeContainerModificationStrategy {
+
+        private final Map<PathArgument, ModificationApplyOperation> childNodes;
+
+        public ChoiceModificationStrategy(final ChoiceNode schemaNode) {
+            super(org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode.class);
+            ImmutableMap.Builder<PathArgument, ModificationApplyOperation> child = ImmutableMap.builder();
+
+            for (ChoiceCaseNode caze : schemaNode.getCases()) {
+                for (DataSchemaNode cazeChild : caze.getChildNodes()) {
+                    SchemaAwareApplyOperation childNode = from(cazeChild);
+                    child.put(new NodeIdentifier(cazeChild.getQName()), childNode);
+                }
+            }
+            childNodes = child.build();
+        }
+
+        @Override
+        public Optional<ModificationApplyOperation> getChild(final PathArgument child) {
+            return Optional.fromNullable(childNodes.get(child));
+        }
+
+        @Override
+        @SuppressWarnings("rawtypes")
+        protected DataContainerNodeBuilder createBuilder(final NormalizedNode<?, ?> original) {
+            checkArgument(original instanceof org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode);
+            return ImmutableChoiceNodeBuilder.create((org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode) original);
+        }
+    }
+
+    public static class OrderedLeafSetModificationStrategy extends NormalizedNodeContainerModificationStrategy {
+
+        private final Optional<ModificationApplyOperation> entryStrategy;
+
+        @SuppressWarnings({ "unchecked", "rawtypes" })
+        protected OrderedLeafSetModificationStrategy(final LeafListSchemaNode schema) {
+            super((Class) LeafSetNode.class);
+            entryStrategy = Optional.<ModificationApplyOperation> of(new LeafSetEntryModificationStrategy(schema));
+        }
+
+        @SuppressWarnings("rawtypes")
+        @Override
+        protected NormalizedNodeContainerBuilder createBuilder(final NormalizedNode<?, ?> original) {
+            checkArgument(original instanceof OrderedLeafSetNode<?>);
+            return ImmutableOrderedLeafSetNodeBuilder.create((OrderedLeafSetNode<?>) original);
+        }
+
+        @Override
+        public Optional<ModificationApplyOperation> getChild(final PathArgument identifier) {
+            if (identifier instanceof NodeWithValue) {
+                return entryStrategy;
+            }
+            return Optional.absent();
+        }
+    }
+
+    public static class OrderedMapModificationStrategy extends NormalizedNodeContainerModificationStrategy {
+
+        private final Optional<ModificationApplyOperation> entryStrategy;
+
+        protected OrderedMapModificationStrategy(final ListSchemaNode schema) {
+            super(OrderedMapNode.class);
+            entryStrategy = Optional.<ModificationApplyOperation> of(new ListEntryModificationStrategy(schema));
+        }
+
+        @SuppressWarnings("rawtypes")
+        @Override
+        protected NormalizedNodeContainerBuilder createBuilder(final NormalizedNode<?, ?> original) {
+            checkArgument(original instanceof OrderedMapNode);
+            return ImmutableOrderedMapNodeBuilder.create((OrderedMapNode) original);
+        }
+
+        @Override
+        public Optional<ModificationApplyOperation> getChild(final PathArgument identifier) {
+            if (identifier instanceof NodeIdentifierWithPredicates) {
+                return entryStrategy;
+            }
+            return Optional.absent();
+        }
+
+        @Override
+        public String toString() {
+            return "OrderedMapModificationStrategy [entry=" + entryStrategy + "]";
+        }
+    }
+
+    public static class UnorderedLeafSetModificationStrategy extends NormalizedNodeContainerModificationStrategy {
+
+        private final Optional<ModificationApplyOperation> entryStrategy;
+
+        @SuppressWarnings({ "unchecked", "rawtypes" })
+        protected UnorderedLeafSetModificationStrategy(final LeafListSchemaNode schema) {
+            super((Class) LeafSetNode.class);
+            entryStrategy = Optional.<ModificationApplyOperation> of(new LeafSetEntryModificationStrategy(schema));
+        }
+
+        @SuppressWarnings("rawtypes")
+        @Override
+        protected NormalizedNodeContainerBuilder createBuilder(final NormalizedNode<?, ?> original) {
+            checkArgument(original instanceof LeafSetNode<?>);
+            return ImmutableLeafSetNodeBuilder.create((LeafSetNode<?>) original);
+        }
+
+        @Override
+        public Optional<ModificationApplyOperation> getChild(final PathArgument identifier) {
+            if (identifier instanceof NodeWithValue) {
+                return entryStrategy;
+            }
+            return Optional.absent();
+        }
+    }
+
+    public static class UnorderedMapModificationStrategy extends NormalizedNodeContainerModificationStrategy {
+
+        private final Optional<ModificationApplyOperation> entryStrategy;
+
+        protected UnorderedMapModificationStrategy(final ListSchemaNode schema) {
+            super(MapNode.class);
+            entryStrategy = Optional.<ModificationApplyOperation> of(new ListEntryModificationStrategy(schema));
+        }
+
+        @SuppressWarnings("rawtypes")
+        @Override
+        protected NormalizedNodeContainerBuilder createBuilder(final NormalizedNode<?, ?> original) {
+            checkArgument(original instanceof MapNode);
+            return ImmutableMapNodeBuilder.create((MapNode) original);
+        }
+
+        @Override
+        public Optional<ModificationApplyOperation> getChild(final PathArgument identifier) {
+            if (identifier instanceof NodeIdentifierWithPredicates) {
+                return entryStrategy;
+            }
+            return Optional.absent();
+        }
+
+        @Override
+        public String toString() {
+            return "UnorderedMapModificationStrategy [entry=" + entryStrategy + "]";
+        }
+    }
+}
\ No newline at end of file
index 02244d9..7afc12c 100644 (file)
@@ -9,48 +9,25 @@ package org.opendaylight.controller.md.sal.dom.store.impl.tree.data;
 
 import static com.google.common.base.Preconditions.checkArgument;
 
-import java.util.HashSet;
 import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ExecutionException;
 
 import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataPreconditionFailedException;
-import org.opendaylight.controller.md.sal.dom.store.impl.tree.StoreUtils;
+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;
+import org.opendaylight.controller.md.sal.dom.store.impl.tree.data.NormalizedNodeContainerModificationStrategy.ChoiceModificationStrategy;
+import org.opendaylight.controller.md.sal.dom.store.impl.tree.data.NormalizedNodeContainerModificationStrategy.OrderedLeafSetModificationStrategy;
+import org.opendaylight.controller.md.sal.dom.store.impl.tree.data.NormalizedNodeContainerModificationStrategy.OrderedMapModificationStrategy;
+import org.opendaylight.controller.md.sal.dom.store.impl.tree.data.NormalizedNodeContainerModificationStrategy.UnorderedLeafSetModificationStrategy;
+import org.opendaylight.controller.md.sal.dom.store.impl.tree.data.ValueNodeModificationStrategy.LeafModificationStrategy;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.AugmentationIdentifier;
 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifier;
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates;
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeWithValue;
 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
-import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
-import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
-import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
-import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
-import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
-import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
-import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
-import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodeContainer;
-import org.opendaylight.yangtools.yang.data.api.schema.OrderedLeafSetNode;
-import org.opendaylight.yangtools.yang.data.api.schema.OrderedMapNode;
-import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListEntryNode;
-import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
-import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeContainerBuilder;
-import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableAugmentationNodeBuilder;
-import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableChoiceNodeBuilder;
-import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableContainerNodeBuilder;
-import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableLeafSetNodeBuilder;
-import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableMapEntryNodeBuilder;
-import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableMapNodeBuilder;
-import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableOrderedLeafSetNodeBuilder;
-import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableOrderedMapNodeBuilder;
-import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableUnkeyedListEntryNodeBuilder;
-import org.opendaylight.yangtools.yang.data.impl.schema.transform.base.AugmentationSchemaProxy;
 import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
 import org.opendaylight.yangtools.yang.model.api.AugmentationTarget;
-import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
 import org.opendaylight.yangtools.yang.model.api.ChoiceNode;
 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
@@ -58,17 +35,15 @@ import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+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.cache.CacheBuilder;
-import com.google.common.cache.CacheLoader;
-import com.google.common.cache.LoadingCache;
-import com.google.common.collect.ImmutableMap;
 import com.google.common.primitives.UnsignedLong;
 
 abstract class SchemaAwareApplyOperation implements ModificationApplyOperation {
+    private static final Logger LOG = LoggerFactory.getLogger(SchemaAwareApplyOperation.class);
 
     public static SchemaAwareApplyOperation from(final DataSchemaNode schemaNode) {
         if (schemaNode instanceof ContainerSchemaNode) {
@@ -85,6 +60,26 @@ abstract class SchemaAwareApplyOperation implements ModificationApplyOperation {
         throw new IllegalArgumentException("Not supported schema node type for " + schemaNode.getClass());
     }
 
+    public static SchemaAwareApplyOperation from(final DataNodeContainer resolvedTree,
+            final AugmentationTarget augSchemas, final AugmentationIdentifier identifier) {
+        AugmentationSchema augSchema = null;
+
+        allAugments:
+            for (AugmentationSchema potential : augSchemas.getAvailableAugmentations()) {
+                for (DataSchemaNode child : potential.getChildNodes()) {
+                    if (identifier.getPossibleChildNames().contains(child.getQName())) {
+                        augSchema = potential;
+                        break allAugments;
+                    }
+                }
+            }
+
+        if (augSchema != null) {
+            return new DataNodeContainerModificationStrategy.AugmentationModificationStrategy(augSchema, resolvedTree);
+        }
+        return null;
+    }
+
     private static SchemaAwareApplyOperation fromListSchemaNode(final ListSchemaNode schemaNode) {
         List<QName> keyDefinition = schemaNode.getKeyDefinition();
         if (keyDefinition == null || keyDefinition.isEmpty()) {
@@ -94,7 +89,7 @@ abstract class SchemaAwareApplyOperation implements ModificationApplyOperation {
             return new OrderedMapModificationStrategy(schemaNode);
         }
 
-        return new UnorderedMapModificationStrategy(schemaNode);
+        return new NormalizedNodeContainerModificationStrategy.UnorderedMapModificationStrategy(schemaNode);
     }
 
     private static SchemaAwareApplyOperation fromLeafListSchemaNode(final LeafListSchemaNode schemaNode) {
@@ -105,25 +100,9 @@ abstract class SchemaAwareApplyOperation implements ModificationApplyOperation {
         }
     }
 
-
-    public static SchemaAwareApplyOperation from(final DataNodeContainer resolvedTree,
-            final AugmentationTarget augSchemas, final AugmentationIdentifier identifier) {
-        AugmentationSchema augSchema = null;
-
-        allAugments:
-            for (AugmentationSchema potential : augSchemas.getAvailableAugmentations()) {
-                for (DataSchemaNode child : potential.getChildNodes()) {
-                    if (identifier.getPossibleChildNames().contains(child.getQName())) {
-                        augSchema = potential;
-                        break allAugments;
-                    }
-                }
-            }
-
-        if (augSchema != null) {
-            return new AugmentationModificationStrategy(augSchema, resolvedTree);
-        }
-        return null;
+    private static final void checkNotConflicting(final InstanceIdentifier path,final StoreMetadataNode original, final StoreMetadataNode current) throws DataPreconditionFailedException {
+        checkDataPrecondition(path, original.getNodeVersion().equals(current.getNodeVersion()),"Node was replaced by other transaction.");
+        checkDataPrecondition(path,original.getSubtreeVersion().equals(current.getSubtreeVersion()), "Node children was modified by other transaction");
     }
 
     protected final ModificationApplyOperation resolveChildOperation(final PathArgument child) {
@@ -139,8 +118,6 @@ abstract class SchemaAwareApplyOperation implements ModificationApplyOperation {
         }
     }
 
-    protected abstract void verifyWrittenStructure(NormalizedNode<?, ?> writtenValue);
-
     @Override
     public void checkApplicable(final InstanceIdentifier path,final NodeModification modification, final Optional<StoreMetadataNode> current) throws DataPreconditionFailedException {
         switch (modification.getModificationType()) {
@@ -188,15 +165,11 @@ abstract class SchemaAwareApplyOperation implements ModificationApplyOperation {
         }
     }
 
-    protected static final void checkNotConflicting(final InstanceIdentifier path,final StoreMetadataNode original, final StoreMetadataNode current) throws DataPreconditionFailedException {
-        checkDataPrecondition(path, original.getNodeVersion().equals(current.getNodeVersion()),"Node was replaced by other transaction.");
-        checkDataPrecondition(path,original.getSubtreeVersion().equals(current.getSubtreeVersion()), "Node children was modified by other transaction");
-    }
-
-    protected abstract void checkSubtreeModificationApplicable(InstanceIdentifier path,final NodeModification modification,
-            final Optional<StoreMetadataNode> current) throws DataPreconditionFailedException;
-
     private void checkDeleteApplicable(final NodeModification modification, final Optional<StoreMetadataNode> current) {
+        // Delete is always applicable, we do not expose it to subclasses
+        if (current.isPresent()) {
+            LOG.trace("Delete operation turned to no-op on missing node {}", modification);
+        }
     }
 
     @Override
@@ -233,402 +206,10 @@ abstract class SchemaAwareApplyOperation implements ModificationApplyOperation {
     protected abstract StoreMetadataNode applySubtreeChange(NodeModification modification,
             StoreMetadataNode currentMeta, UnsignedLong subtreeVersion);
 
-    public static abstract class ValueNodeModificationStrategy<T extends DataSchemaNode> extends SchemaAwareApplyOperation {
-
-        private final T schema;
-        private final Class<? extends NormalizedNode<?, ?>> nodeClass;
-
-        protected ValueNodeModificationStrategy(final T schema, final Class<? extends NormalizedNode<?, ?>> nodeClass) {
-            super();
-            this.schema = schema;
-            this.nodeClass = nodeClass;
-        }
-
-        @Override
-        protected void verifyWrittenStructure(final NormalizedNode<?, ?> writtenValue) {
-            checkArgument(nodeClass.isInstance(writtenValue), "Node should must be of type %s", nodeClass);
-        }
-
-        @Override
-        public Optional<ModificationApplyOperation> getChild(final PathArgument child) {
-            throw new UnsupportedOperationException("Node " + schema.getPath()
-                    + "is leaf type node. Child nodes not allowed");
-        }
-
-        @Override
-        protected StoreMetadataNode applySubtreeChange(final NodeModification modification,
-                final StoreMetadataNode currentMeta, final UnsignedLong subtreeVersion) {
-            throw new UnsupportedOperationException("Node " + schema.getPath()
-                    + "is leaf type node. Subtree change is not allowed.");
-        }
-
-        @Override
-        protected StoreMetadataNode applyMerge(final NodeModification modification, final StoreMetadataNode currentMeta,
-                final UnsignedLong subtreeVersion) {
-            return applyWrite(modification, Optional.of(currentMeta), subtreeVersion);
-        }
-
-        @Override
-        protected StoreMetadataNode applyWrite(final NodeModification modification,
-                final Optional<StoreMetadataNode> currentMeta, final UnsignedLong subtreeVersion) {
-            UnsignedLong nodeVersion = subtreeVersion;
-            return StoreMetadataNode.builder().setNodeVersion(nodeVersion).setSubtreeVersion(subtreeVersion)
-                    .setData(modification.getWrittenValue()).build();
-        }
-
-        @Override
-        protected void checkSubtreeModificationApplicable(final InstanceIdentifier path,final NodeModification modification,
-                final Optional<StoreMetadataNode> current) throws DataPreconditionFailedException {
-            throw new DataPreconditionFailedException(path, "Subtree modification is not allowed.");
-        }
-
-    }
-
-    public static class LeafSetEntryModificationStrategy extends ValueNodeModificationStrategy<LeafListSchemaNode> {
-
-        @SuppressWarnings({ "unchecked", "rawtypes" })
-        protected LeafSetEntryModificationStrategy(final LeafListSchemaNode schema) {
-            super(schema, (Class) LeafSetEntryNode.class);
-        }
-    }
-
-    public static class LeafModificationStrategy extends ValueNodeModificationStrategy<LeafSchemaNode> {
-
-        @SuppressWarnings({ "unchecked", "rawtypes" })
-        protected LeafModificationStrategy(final LeafSchemaNode schema) {
-            super(schema, (Class) LeafNode.class);
-        }
-    }
-
-    public static abstract class NormalizedNodeContainerModificationStrategy extends SchemaAwareApplyOperation {
-
-        private final Class<? extends NormalizedNode<?, ?>> nodeClass;
-
-        protected NormalizedNodeContainerModificationStrategy(final Class<? extends NormalizedNode<?, ?>> nodeClass) {
-            this.nodeClass = nodeClass;
-        }
-
-        @Override
-        public void verifyStructure(final NodeModification modification) throws IllegalArgumentException {
-            if (modification.getModificationType() == ModificationType.WRITE) {
-
-            }
-            for (NodeModification childModification : modification.getModifications()) {
-                resolveChildOperation(childModification.getIdentifier()).verifyStructure(childModification);
-            }
-        }
-
-        @Override
-        protected void checkWriteApplicable(final InstanceIdentifier path, final NodeModification modification,
-                final Optional<StoreMetadataNode> current) throws DataPreconditionFailedException {
-            // 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.
-        }
-
-        @SuppressWarnings("rawtypes")
-        @Override
-        protected void verifyWrittenStructure(final NormalizedNode<?, ?> writtenValue) {
-            checkArgument(nodeClass.isInstance(writtenValue), "Node should must be of type %s", nodeClass);
-            checkArgument(writtenValue instanceof NormalizedNodeContainer);
-
-            NormalizedNodeContainer container = (NormalizedNodeContainer) writtenValue;
-            for (Object child : container.getValue()) {
-                checkArgument(child instanceof NormalizedNode);
-
-                /*
-                 * FIXME: fail-fast semantics:
-                 *
-                 * We can validate the data structure here, aborting the commit
-                 * before it ever progresses to being committed.
-                 */
-            }
-        }
-
-        @Override
-        protected StoreMetadataNode applyWrite(final NodeModification modification,
-                final Optional<StoreMetadataNode> currentMeta, final UnsignedLong subtreeVersion) {
-
-            NormalizedNode<?, ?> newValue = modification.getWrittenValue();
-
-            final UnsignedLong nodeVersion;
-            if (currentMeta.isPresent()) {
-                nodeVersion = StoreUtils.increase(currentMeta.get().getNodeVersion());
-            } else {
-                nodeVersion = subtreeVersion;
-            }
-
-            final StoreMetadataNode newValueMeta = StoreMetadataNode.createRecursively(newValue, nodeVersion, nodeVersion);
-            if (!modification.hasAdditionalModifications()) {
-                return newValueMeta;
-            }
-
-            @SuppressWarnings("rawtypes")
-            NormalizedNodeContainerBuilder dataBuilder = createBuilder(newValue);
-            StoreNodeCompositeBuilder builder = StoreNodeCompositeBuilder.from(dataBuilder) //
-                    .setNodeVersion(nodeVersion) //
-                    .setSubtreeVersion(subtreeVersion);
-
-            return mutateChildren(modification.getModifications(), newValueMeta, builder, nodeVersion);
-        }
-
-        @Override
-        protected StoreMetadataNode applyMerge(final NodeModification modification, final StoreMetadataNode currentMeta,
-                final UnsignedLong subtreeVersion) {
-            // For Node Containers - merge is same as subtree change - we only replace children.
-            return applySubtreeChange(modification, currentMeta, subtreeVersion);
-        }
-
-        @Override
-        public StoreMetadataNode applySubtreeChange(final NodeModification modification,
-                final StoreMetadataNode currentMeta, final UnsignedLong subtreeVersion) {
-            // Bump subtree version to its new target
-            final UnsignedLong updatedSubtreeVersion = StoreUtils.increase(currentMeta.getSubtreeVersion());
-
-            @SuppressWarnings("rawtypes")
-            NormalizedNodeContainerBuilder dataBuilder = createBuilder(currentMeta.getData());
-            StoreNodeCompositeBuilder builder = StoreNodeCompositeBuilder.from(dataBuilder, currentMeta)
-                    .setIdentifier(modification.getIdentifier()).setNodeVersion(currentMeta.getNodeVersion())
-                    .setSubtreeVersion(updatedSubtreeVersion);
-
-            return mutateChildren(modification.getModifications(), currentMeta, builder, updatedSubtreeVersion);
-        }
-
-        private StoreMetadataNode mutateChildren(final Iterable<NodeModification> modifications, final StoreMetadataNode meta,
-                final StoreNodeCompositeBuilder builder, final UnsignedLong nodeVersion) {
-
-            for (NodeModification mod : modifications) {
-                final PathArgument id = mod.getIdentifier();
-                final Optional<StoreMetadataNode> cm = meta.getChild(id);
-
-                Optional<StoreMetadataNode> result = resolveChildOperation(id).apply(mod, cm, nodeVersion);
-                if (result.isPresent()) {
-                    builder.add(result.get());
-                } else {
-                    builder.remove(id);
-                }
-            }
-
-            return builder.build();
-        }
-
-        @Override
-        protected void checkSubtreeModificationApplicable(final InstanceIdentifier path,final NodeModification modification,
-                final Optional<StoreMetadataNode> current) throws DataPreconditionFailedException {
-            checkDataPrecondition(path, current.isPresent(), "Node was deleted by other transaction.");
-            checkChildPreconditions(path,modification,current);
-
-        }
-
-        private void checkChildPreconditions(final InstanceIdentifier path, final NodeModification modification, final Optional<StoreMetadataNode> current) throws DataPreconditionFailedException {
-            StoreMetadataNode currentMeta = current.get();
-            for (NodeModification childMod : modification.getModifications()) {
-                PathArgument childId = childMod.getIdentifier();
-                Optional<StoreMetadataNode> childMeta = currentMeta.getChild(childId);
-                InstanceIdentifier childPath = StoreUtils.append(path, childId);
-                resolveChildOperation(childId).checkApplicable(childPath,childMod, childMeta);
-            }
-        }
-
-        @Override
-        protected void checkMergeApplicable(final InstanceIdentifier path, final NodeModification modification,
-                final Optional<StoreMetadataNode> current) throws DataPreconditionFailedException {
-            if(current.isPresent()) {
-                checkChildPreconditions(path,modification,current);
-            }
-        }
-
-        @SuppressWarnings("rawtypes")
-        protected abstract NormalizedNodeContainerBuilder createBuilder(NormalizedNode<?, ?> original);
-    }
-
-    public static abstract class DataNodeContainerModificationStrategy<T extends DataNodeContainer> extends NormalizedNodeContainerModificationStrategy {
-
-        private final T schema;
-        private final LoadingCache<PathArgument, ModificationApplyOperation> childCache = CacheBuilder.newBuilder()
-                .build(CacheLoader.from(new Function<PathArgument, ModificationApplyOperation>() {
-
-                    @Override
-                    public ModificationApplyOperation apply(final PathArgument identifier) {
-                        if (identifier instanceof AugmentationIdentifier && schema instanceof AugmentationTarget) {
-                            return from(schema, (AugmentationTarget) schema, (AugmentationIdentifier) identifier);
-                        }
-
-                        DataSchemaNode child = schema.getDataChildByName(identifier.getNodeType());
-                        if (child == null) {
-                            return null;
-                        }
-                        return from(child);
-                    }
-                }));
-
-        protected DataNodeContainerModificationStrategy(final T schema,
-                final Class<? extends NormalizedNode<?, ?>> nodeClass) {
-            super(nodeClass);
-            this.schema = schema;
-        }
-
-        protected T getSchema() {
-            return schema;
-        }
-
-        @Override
-        public Optional<ModificationApplyOperation> getChild(final PathArgument identifier) {
-            try {
-                return Optional.<ModificationApplyOperation> fromNullable(childCache.get(identifier));
-            } catch (ExecutionException e) {
-                return Optional.absent();
-            }
-        }
-
-        @Override
-        @SuppressWarnings("rawtypes")
-        protected abstract DataContainerNodeBuilder createBuilder(NormalizedNode<?, ?> original);
-
-        @Override
-        public String toString() {
-            return getClass().getSimpleName() + " [" + schema + "]";
-        }
-
-    }
-
-    public static class ContainerModificationStrategy extends DataNodeContainerModificationStrategy<ContainerSchemaNode> {
-
-        public ContainerModificationStrategy(final ContainerSchemaNode schemaNode) {
-            super(schemaNode, ContainerNode.class);
-        }
-
-        @Override
-        @SuppressWarnings("rawtypes")
-        protected DataContainerNodeBuilder createBuilder(final NormalizedNode<?, ?> original) {
-            checkArgument(original instanceof ContainerNode);
-            return ImmutableContainerNodeBuilder.create((ContainerNode) original);
-        }
-    }
-
-    public static class UnkeyedListItemModificationStrategy extends DataNodeContainerModificationStrategy<ListSchemaNode> {
-
-        public UnkeyedListItemModificationStrategy(final ListSchemaNode schemaNode) {
-            super(schemaNode, UnkeyedListEntryNode.class);
-        }
-
-        @Override
-        @SuppressWarnings("rawtypes")
-        protected DataContainerNodeBuilder createBuilder(final NormalizedNode<?, ?> original) {
-            checkArgument(original instanceof UnkeyedListEntryNode);
-            return ImmutableUnkeyedListEntryNodeBuilder.create((UnkeyedListEntryNode) original);
-        }
-    }
-
-    public static class AugmentationModificationStrategy extends DataNodeContainerModificationStrategy<AugmentationSchema> {
-
-        protected AugmentationModificationStrategy(final AugmentationSchema schema, final DataNodeContainer resolved) {
-            super(createAugmentProxy(schema,resolved), AugmentationNode.class);
-        }
-
-        @Override
-        @SuppressWarnings("rawtypes")
-        protected DataContainerNodeBuilder createBuilder(final NormalizedNode<?, ?> original) {
-            checkArgument(original instanceof AugmentationNode);
-            return ImmutableAugmentationNodeBuilder.create((AugmentationNode) original);
-        }
-    }
-
-    public static class ChoiceModificationStrategy extends NormalizedNodeContainerModificationStrategy {
-
-        private final Map<PathArgument, ModificationApplyOperation> childNodes;
-
-        public ChoiceModificationStrategy(final ChoiceNode schemaNode) {
-            super(org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode.class);
-            ImmutableMap.Builder<PathArgument, ModificationApplyOperation> child = ImmutableMap.builder();
-
-            for (ChoiceCaseNode caze : schemaNode.getCases()) {
-                for (DataSchemaNode cazeChild : caze.getChildNodes()) {
-                    SchemaAwareApplyOperation childNode = from(cazeChild);
-                    child.put(new NodeIdentifier(cazeChild.getQName()), childNode);
-                }
-            }
-            childNodes = child.build();
-        }
-
-        @Override
-        public Optional<ModificationApplyOperation> getChild(final PathArgument child) {
-            return Optional.fromNullable(childNodes.get(child));
-        }
-
-        @Override
-        @SuppressWarnings("rawtypes")
-        protected DataContainerNodeBuilder createBuilder(final NormalizedNode<?, ?> original) {
-            checkArgument(original instanceof org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode);
-            return ImmutableChoiceNodeBuilder.create((org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode) original);
-        }
-    }
-
-    public static class ListEntryModificationStrategy extends DataNodeContainerModificationStrategy<ListSchemaNode> {
-
-        protected ListEntryModificationStrategy(final ListSchemaNode schema) {
-            super(schema, MapEntryNode.class);
-        }
-
-        @Override
-        @SuppressWarnings("rawtypes")
-        protected final DataContainerNodeBuilder createBuilder(final NormalizedNode<?, ?> original) {
-            checkArgument(original instanceof MapEntryNode);
-            return ImmutableMapEntryNodeBuilder.create((MapEntryNode) original);
-        }
-    }
-
-    public static class UnorderedLeafSetModificationStrategy extends NormalizedNodeContainerModificationStrategy {
-
-        private final Optional<ModificationApplyOperation> entryStrategy;
-
-        @SuppressWarnings({ "unchecked", "rawtypes" })
-        protected UnorderedLeafSetModificationStrategy(final LeafListSchemaNode schema) {
-            super((Class) LeafSetNode.class);
-            entryStrategy = Optional.<ModificationApplyOperation> of(new LeafSetEntryModificationStrategy(schema));
-        }
-
-        @SuppressWarnings("rawtypes")
-        @Override
-        protected NormalizedNodeContainerBuilder createBuilder(final NormalizedNode<?, ?> original) {
-            checkArgument(original instanceof LeafSetNode<?>);
-            return ImmutableLeafSetNodeBuilder.create((LeafSetNode<?>) original);
-        }
-
-        @Override
-        public Optional<ModificationApplyOperation> getChild(final PathArgument identifier) {
-            if (identifier instanceof NodeWithValue) {
-                return entryStrategy;
-            }
-            return Optional.absent();
-        }
-    }
-
-    public static class OrderedLeafSetModificationStrategy extends NormalizedNodeContainerModificationStrategy {
-
-        private final Optional<ModificationApplyOperation> entryStrategy;
-
-        @SuppressWarnings({ "unchecked", "rawtypes" })
-        protected OrderedLeafSetModificationStrategy(final LeafListSchemaNode schema) {
-            super((Class) LeafSetNode.class);
-            entryStrategy = Optional.<ModificationApplyOperation> of(new LeafSetEntryModificationStrategy(schema));
-        }
-
-        @SuppressWarnings("rawtypes")
-        @Override
-        protected NormalizedNodeContainerBuilder createBuilder(final NormalizedNode<?, ?> original) {
-            checkArgument(original instanceof OrderedLeafSetNode<?>);
-            return ImmutableOrderedLeafSetNodeBuilder.create((OrderedLeafSetNode<?>) original);
-        }
+    protected abstract void checkSubtreeModificationApplicable(InstanceIdentifier path,final NodeModification modification,
+            final Optional<StoreMetadataNode> current) throws DataPreconditionFailedException;
 
-        @Override
-        public Optional<ModificationApplyOperation> getChild(final PathArgument identifier) {
-            if (identifier instanceof NodeWithValue) {
-                return entryStrategy;
-            }
-            return Optional.absent();
-        }
-    }
+    protected abstract void verifyWrittenStructure(NormalizedNode<?, ?> writtenValue);
 
     public static class UnkeyedListModificationStrategy extends SchemaAwareApplyOperation {
 
@@ -674,75 +255,6 @@ abstract class SchemaAwareApplyOperation implements ModificationApplyOperation {
                 final Optional<StoreMetadataNode> current) throws DataPreconditionFailedException {
             throw new DataPreconditionFailedException(path, "Subtree modification is not allowed.");
         }
-
-    }
-
-    public static class UnorderedMapModificationStrategy extends NormalizedNodeContainerModificationStrategy {
-
-        private final Optional<ModificationApplyOperation> entryStrategy;
-
-        protected UnorderedMapModificationStrategy(final ListSchemaNode schema) {
-            super(MapNode.class);
-            entryStrategy = Optional.<ModificationApplyOperation> of(new ListEntryModificationStrategy(schema));
-        }
-
-        @SuppressWarnings("rawtypes")
-        @Override
-        protected NormalizedNodeContainerBuilder createBuilder(final NormalizedNode<?, ?> original) {
-            checkArgument(original instanceof MapNode);
-            return ImmutableMapNodeBuilder.create((MapNode) original);
-        }
-
-        @Override
-        public Optional<ModificationApplyOperation> getChild(final PathArgument identifier) {
-            if (identifier instanceof NodeIdentifierWithPredicates) {
-                return entryStrategy;
-            }
-            return Optional.absent();
-        }
-
-        @Override
-        public String toString() {
-            return "UnorderedMapModificationStrategy [entry=" + entryStrategy + "]";
-        }
-    }
-
-    public static class OrderedMapModificationStrategy extends NormalizedNodeContainerModificationStrategy {
-
-        private final Optional<ModificationApplyOperation> entryStrategy;
-
-        protected OrderedMapModificationStrategy(final ListSchemaNode schema) {
-            super(OrderedMapNode.class);
-            entryStrategy = Optional.<ModificationApplyOperation> of(new ListEntryModificationStrategy(schema));
-        }
-
-        @SuppressWarnings("rawtypes")
-        @Override
-        protected NormalizedNodeContainerBuilder createBuilder(final NormalizedNode<?, ?> original) {
-            checkArgument(original instanceof OrderedMapNode);
-            return ImmutableOrderedMapNodeBuilder.create((OrderedMapNode) original);
-        }
-
-        @Override
-        public Optional<ModificationApplyOperation> getChild(final PathArgument identifier) {
-            if (identifier instanceof NodeIdentifierWithPredicates) {
-                return entryStrategy;
-            }
-            return Optional.absent();
-        }
-
-        @Override
-        public String toString() {
-            return "OrderedMapModificationStrategy [entry=" + entryStrategy + "]";
-        }
-    }
-
-    public static AugmentationSchema createAugmentProxy(final AugmentationSchema schema, final DataNodeContainer resolved) {
-        Set<DataSchemaNode> realChildSchemas = new HashSet<>();
-        for(DataSchemaNode augChild : schema.getChildNodes()) {
-            realChildSchemas.add(resolved.getDataChildByName(augChild.getQName()));
-        }
-        return new AugmentationSchemaProxy(schema, realChildSchemas);
     }
 
     public static boolean checkDataPrecondition(final InstanceIdentifier path, final boolean condition, final String message) throws DataPreconditionFailedException {
index 8addb89..695a1f1 100644 (file)
@@ -13,7 +13,6 @@ import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
 
-import org.opendaylight.controller.md.sal.dom.store.impl.tree.StoreTreeNode;
 import org.opendaylight.yangtools.concepts.Identifiable;
 import org.opendaylight.yangtools.concepts.Immutable;
 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
@@ -24,15 +23,12 @@ import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
 import com.google.common.primitives.UnsignedLong;
 
-// FIXME: this should not be public
-public class StoreMetadataNode implements Immutable, Identifiable<PathArgument>, StoreTreeNode<StoreMetadataNode> {
-
+class StoreMetadataNode implements Immutable, Identifiable<PathArgument> {
+    private final Map<PathArgument, StoreMetadataNode> children;
     private final UnsignedLong nodeVersion;
     private final UnsignedLong subtreeVersion;
     private final NormalizedNode<?, ?> data;
 
-    private final Map<PathArgument, StoreMetadataNode> children;
-
     /**
      *
      * @param data
@@ -40,11 +36,11 @@ public class StoreMetadataNode implements Immutable, Identifiable<PathArgument>,
      * @param subtreeVersion
      * @param children Map of children, must not be modified externally
      */
-    protected StoreMetadataNode(final NormalizedNode<?, ?> data, final UnsignedLong nodeVersion,
+    private StoreMetadataNode(final NormalizedNode<?, ?> data, final UnsignedLong nodeVersion,
             final UnsignedLong subtreeVersion, final Map<PathArgument, StoreMetadataNode> children) {
-        this.nodeVersion = nodeVersion;
-        this.subtreeVersion = subtreeVersion;
-        this.data = data;
+        this.nodeVersion = Preconditions.checkNotNull(nodeVersion);
+        this.subtreeVersion = Preconditions.checkNotNull(subtreeVersion);
+        this.data = Preconditions.checkNotNull(data);
         this.children = Preconditions.checkNotNull(children);
     }
 
@@ -53,16 +49,11 @@ public class StoreMetadataNode implements Immutable, Identifiable<PathArgument>,
                 Collections.<PathArgument, StoreMetadataNode>emptyMap());
     }
 
-    public StoreMetadataNode(final NormalizedNode<?, ?> data, final UnsignedLong nodeVersion,
-            final UnsignedLong subtreeVersion) {
-        this(data, nodeVersion, subtreeVersion, Collections.<PathArgument, StoreMetadataNode>emptyMap());
-    }
-
-    public static Builder builder() {
-        return new Builder();
+    public static Builder builder(final UnsignedLong version) {
+        return new Builder(version);
     }
 
-    public static Builder builder(StoreMetadataNode node) {
+    public static Builder builder(final StoreMetadataNode node) {
         return new Builder(node);
     }
 
@@ -83,8 +74,7 @@ public class StoreMetadataNode implements Immutable, Identifiable<PathArgument>,
         return this.data;
     }
 
-    @Override
-    public Optional<StoreMetadataNode> getChild(final PathArgument key) {
+    Optional<StoreMetadataNode> getChild(final PathArgument key) {
         return Optional.fromNullable(children.get(key));
     }
 
@@ -93,33 +83,17 @@ public class StoreMetadataNode implements Immutable, Identifiable<PathArgument>,
         return "StoreMetadataNode [identifier=" + getIdentifier() + ", nodeVersion=" + nodeVersion + "]";
     }
 
-    public static Optional<UnsignedLong> getVersion(final Optional<StoreMetadataNode> currentMetadata) {
-        if (currentMetadata.isPresent()) {
-            return Optional.of(currentMetadata.get().getNodeVersion());
-        }
-        return Optional.absent();
-    }
-
-    public static Optional<StoreMetadataNode> getChild(final Optional<StoreMetadataNode> parent,
-            final PathArgument child) {
-        if (parent.isPresent()) {
-            return parent.get().getChild(child);
-        }
-        return Optional.absent();
-    }
-
     public static final StoreMetadataNode createRecursively(final NormalizedNode<?, ?> node,
-            final UnsignedLong nodeVersion, final UnsignedLong subtreeVersion) {
-        Builder builder = builder() //
-                .setNodeVersion(nodeVersion) //
-                .setSubtreeVersion(subtreeVersion) //
+            final UnsignedLong version) {
+        Builder builder = builder(version) //
+                .setSubtreeVersion(version) //
                 .setData(node);
         if (node instanceof NormalizedNodeContainer<?, ?, ?>) {
 
             @SuppressWarnings("unchecked")
             NormalizedNodeContainer<?, ?, NormalizedNode<?, ?>> nodeContainer = (NormalizedNodeContainer<?, ?, NormalizedNode<?, ?>>) node;
             for (NormalizedNode<?, ?> subNode : nodeContainer.getValue()) {
-                builder.add(createRecursively(subNode, nodeVersion, subtreeVersion));
+                builder.add(createRecursively(subNode, version));
             }
         }
         return builder.build();
@@ -127,30 +101,22 @@ public class StoreMetadataNode implements Immutable, Identifiable<PathArgument>,
 
     public static class Builder {
 
-        private UnsignedLong nodeVersion;
+        private final UnsignedLong nodeVersion;
         private UnsignedLong subtreeVersion;
         private NormalizedNode<?, ?> data;
         private Map<PathArgument, StoreMetadataNode> children;
         private boolean dirty = false;
 
-        private Builder() {
+        private Builder(final UnsignedLong version) {
+            this.nodeVersion = Preconditions.checkNotNull(version);
             children = new HashMap<>();
         }
 
-        public Builder(StoreMetadataNode node) {
+        private Builder(final StoreMetadataNode node) {
+            this.nodeVersion = node.getNodeVersion();
             children = new HashMap<>(node.children);
         }
 
-        public UnsignedLong getVersion() {
-            return nodeVersion;
-
-        }
-
-        public Builder setNodeVersion(final UnsignedLong version) {
-            this.nodeVersion = version;
-            return this;
-        }
-
         public Builder setSubtreeVersion(final UnsignedLong version) {
             this.subtreeVersion = version;
             return this;
@@ -188,7 +154,4 @@ public class StoreMetadataNode implements Immutable, Identifiable<PathArgument>,
         }
     }
 
-    public static StoreMetadataNode createRecursively(final NormalizedNode<?, ?> node, final UnsignedLong version) {
-        return createRecursively(node, version, version);
-    }
 }
index 6bce4ff..19debbb 100644 (file)
@@ -26,12 +26,12 @@ class StoreNodeCompositeBuilder {
 
     private final NormalizedNodeContainerBuilder data;
 
-    private StoreNodeCompositeBuilder(final NormalizedNodeContainerBuilder nodeBuilder) {
-        this.metadata = StoreMetadataNode.builder();
+    private StoreNodeCompositeBuilder(final UnsignedLong version, final NormalizedNodeContainerBuilder nodeBuilder) {
+        this.metadata = StoreMetadataNode.builder(version);
         this.data = Preconditions.checkNotNull(nodeBuilder);
     }
 
-    public StoreNodeCompositeBuilder(NormalizedNodeContainerBuilder nodeBuilder, StoreMetadataNode currentMeta) {
+    private StoreNodeCompositeBuilder(final NormalizedNodeContainerBuilder nodeBuilder, final StoreMetadataNode currentMeta) {
         this.metadata = StoreMetadataNode.builder(currentMeta);
         this.data = Preconditions.checkNotNull(nodeBuilder);
     }
@@ -44,7 +44,7 @@ class StoreNodeCompositeBuilder {
     }
 
     @SuppressWarnings("unchecked")
-    public StoreNodeCompositeBuilder remove(PathArgument id) {
+    public StoreNodeCompositeBuilder remove(final PathArgument id) {
         metadata.remove(id);
         data.removeChild(id);
         return this;
@@ -54,11 +54,11 @@ class StoreNodeCompositeBuilder {
         return metadata.setData(data.build()).build();
     }
 
-    public static StoreNodeCompositeBuilder from(final NormalizedNodeContainerBuilder nodeBuilder) {
-        return new StoreNodeCompositeBuilder(nodeBuilder);
+    public static StoreNodeCompositeBuilder create(final UnsignedLong version, final NormalizedNodeContainerBuilder nodeBuilder) {
+        return new StoreNodeCompositeBuilder(version, nodeBuilder);
     }
 
-    public static StoreNodeCompositeBuilder from(final NormalizedNodeContainerBuilder nodeBuilder, StoreMetadataNode currentMeta) {
+    public static StoreNodeCompositeBuilder create(final NormalizedNodeContainerBuilder nodeBuilder, final StoreMetadataNode currentMeta) {
         return new StoreNodeCompositeBuilder(nodeBuilder, currentMeta);
     }
 
@@ -68,11 +68,6 @@ class StoreNodeCompositeBuilder {
         return this;
     }
 
-    public StoreNodeCompositeBuilder setNodeVersion(final UnsignedLong nodeVersion) {
-        metadata.setNodeVersion(nodeVersion);
-        return this;
-    }
-
     public StoreNodeCompositeBuilder setSubtreeVersion(final UnsignedLong updatedSubtreeVersion) {
         metadata.setSubtreeVersion(updatedSubtreeVersion);
         return this;
diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/ValueNodeModificationStrategy.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/ValueNodeModificationStrategy.java
new file mode 100644 (file)
index 0000000..2892953
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * 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.data;
+
+ import static com.google.common.base.Preconditions.checkArgument;
+
+import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataPreconditionFailedException;
+ import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+ import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
+ import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
+ import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
+ import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+ import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+ import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
+ import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+
+import com.google.common.base.Optional;
+ import com.google.common.primitives.UnsignedLong;
+
+ abstract class ValueNodeModificationStrategy<T extends DataSchemaNode> extends SchemaAwareApplyOperation {
+
+     private final T schema;
+     private final Class<? extends NormalizedNode<?, ?>> nodeClass;
+
+     protected ValueNodeModificationStrategy(final T schema, final Class<? extends NormalizedNode<?, ?>> nodeClass) {
+         super();
+         this.schema = schema;
+         this.nodeClass = nodeClass;
+     }
+
+     @Override
+     protected void verifyWrittenStructure(final NormalizedNode<?, ?> writtenValue) {
+         checkArgument(nodeClass.isInstance(writtenValue), "Node should must be of type %s", nodeClass);
+     }
+
+     @Override
+     public Optional<ModificationApplyOperation> getChild(final PathArgument child) {
+         throw new UnsupportedOperationException("Node " + schema.getPath()
+                 + "is leaf type node. Child nodes not allowed");
+     }
+
+     @Override
+     protected StoreMetadataNode applySubtreeChange(final NodeModification modification,
+             final StoreMetadataNode currentMeta, final UnsignedLong subtreeVersion) {
+         throw new UnsupportedOperationException("Node " + schema.getPath()
+                 + "is leaf type node. Subtree change is not allowed.");
+     }
+
+     @Override
+     protected StoreMetadataNode applyMerge(final NodeModification modification, final StoreMetadataNode currentMeta,
+             final UnsignedLong subtreeVersion) {
+         return applyWrite(modification, Optional.of(currentMeta), subtreeVersion);
+     }
+
+     @Override
+     protected StoreMetadataNode applyWrite(final NodeModification modification,
+             final Optional<StoreMetadataNode> currentMeta, final UnsignedLong subtreeVersion) {
+         return StoreMetadataNode.builder(subtreeVersion).setSubtreeVersion(subtreeVersion)
+                 .setData(modification.getWrittenValue()).build();
+     }
+
+     @Override
+     protected void checkSubtreeModificationApplicable(final InstanceIdentifier path,final NodeModification modification,
+             final Optional<StoreMetadataNode> current) throws DataPreconditionFailedException {
+         throw new DataPreconditionFailedException(path, "Subtree modification is not allowed.");
+     }
+
+     public static class LeafSetEntryModificationStrategy extends ValueNodeModificationStrategy<LeafListSchemaNode> {
+         @SuppressWarnings({ "unchecked", "rawtypes" })
+         protected LeafSetEntryModificationStrategy(final LeafListSchemaNode schema) {
+             super(schema, (Class) LeafSetEntryNode.class);
+         }
+     }
+
+     public static class LeafModificationStrategy extends ValueNodeModificationStrategy<LeafSchemaNode> {
+         @SuppressWarnings({ "unchecked", "rawtypes" })
+         protected LeafModificationStrategy(final LeafSchemaNode schema) {
+             super(schema, (Class) LeafNode.class);
+         }
+     }
+ }
\ No newline at end of file
index f2cc533..03ece2f 100644 (file)
@@ -14,7 +14,7 @@ import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableCo
 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 
-public class SchemaAwareApplyOperationRoot extends SchemaAwareApplyOperation.DataNodeContainerModificationStrategy<ContainerSchemaNode> {
+public class SchemaAwareApplyOperationRoot extends DataNodeContainerModificationStrategy<ContainerSchemaNode> {
     private final SchemaContext context;
 
     public SchemaAwareApplyOperationRoot(final SchemaContext context) {
index c17a4b7..e4c7c0c 100644 (file)
       <groupId>org.opendaylight.yangtools</groupId>
       <artifactId>yang-parser-impl</artifactId>
     </dependency>
+    <dependency>
+      <groupId>org.opendaylight.yangtools.model</groupId>
+      <artifactId>ietf-restconf</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.yangtools.model</groupId>
+      <artifactId>ietf-yang-types-20130715</artifactId>
+    </dependency>
     <dependency>
       <groupId>org.slf4j</groupId>
       <artifactId>slf4j-api</artifactId>
index 423d2e4..8954c05 100644 (file)
@@ -7,7 +7,6 @@
     <version>1.1-SNAPSHOT</version>
   </parent>
 
-  <groupId>org.opendaylight.controller</groupId>
   <artifactId>sal-rest-docgen</artifactId>
   <packaging>bundle</packaging>
 
@@ -94,7 +93,6 @@
       <plugin>
         <groupId>org.apache.felix</groupId>
         <artifactId>maven-bundle-plugin</artifactId>
-        <version>2.4.0</version>
         <extensions>true</extensions>
         <configuration>
 
index cb8f660..8f6a7cd 100644 (file)
@@ -12,13 +12,8 @@ import com.google.common.base.Preconditions;
 import java.util.List;
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
 import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 public class SimpleAttributeReadingStrategy extends AbstractAttributeReadingStrategy {
-    private static final Logger logger = LoggerFactory.getLogger(SimpleAttributeReadingStrategy.class);
-
-
     public SimpleAttributeReadingStrategy(String nullableDefault) {
         super(nullableDefault);
     }
@@ -29,20 +24,7 @@ public class SimpleAttributeReadingStrategy extends AbstractAttributeReadingStra
         Preconditions.checkState(configNodes.size() == 1, "This element should be present only once " + xmlElement
                 + " but was " + configNodes.size());
 
-        String textContent = "";
-        try{
-            textContent = readElementContent(xmlElement);
-        }catch(IllegalStateException | NullPointerException e) {
-            // yuma sends <attribute /> for empty value instead of <attribute></attribute>
-            logger.warn("Ignoring exception caused by failure to read text element", e);
-        }
-
-        if (null == textContent){
-            throw new NetconfDocumentedException(String.format("This element should contain text %s", xmlElement),
-                    NetconfDocumentedException.ErrorType.application,
-                    NetconfDocumentedException.ErrorTag.invalid_value,
-                    NetconfDocumentedException.ErrorSeverity.error);
-        }
+        String textContent = readElementContent(xmlElement);
         return AttributeConfigElement.create(postprocessNullableDefault(getNullableDefault()),
                 postprocessParsedValue(textContent));
     }
index 66b945d..68c8c6f 100644 (file)
@@ -40,8 +40,9 @@ public class ObjectNameAttributeWritingStrategy implements AttributeWritingStrat
         String refName = ((ObjectNameAttributeMappingStrategy.MappedDependency) value).getRefName();
         String namespaceForType = ((ObjectNameAttributeMappingStrategy.MappedDependency) value).getNamespace();
 
-        Element typeElement = XmlUtil.createPrefixedTextElement(document, XmlUtil.createPrefixedValue(XmlNetconfConstants.PREFIX, XmlNetconfConstants.TYPE_KEY), XmlNetconfConstants.PREFIX,
-                moduleName, Optional.<String>of(namespaceForType));
+        Element typeElement = XmlUtil.createTextElementWithNamespacedContent(document,  XmlNetconfConstants.TYPE_KEY, XmlNetconfConstants.PREFIX,
+                namespaceForType, moduleName);
+
         innerNode.appendChild(typeElement);
 
         final Element nameElement = XmlUtil.createTextElement(document, XmlNetconfConstants.NAME_KEY, refName, Optional.<String>absent());
index ed3bb2a..a2b8e0b 100644 (file)
@@ -43,9 +43,8 @@ public class SimpleIdentityRefAttributeWritingStrategy extends SimpleAttributeWr
     @Override
     protected Element createElement(Document doc, String key, String value, Optional<String> namespace) {
         QName qName = QName.create(value);
-        String identity = qName.getLocalName();
+        String identityValue = qName.getLocalName();
         String identityNamespace = qName.getNamespace().toString();
-        Element element = XmlUtil.createPrefixedTextElement(doc, XmlUtil.createPrefixedValue(PREFIX, key), PREFIX, identity, Optional.<String>of(identityNamespace));
-        return element;
+        return XmlUtil.createTextElementWithNamespacedContent(doc, key, PREFIX, identityNamespace, identityValue);
     }
 }
index a5a625a..6a17e97 100644 (file)
@@ -60,19 +60,17 @@ public class ModuleConfig {
 
     public Element toXml(ObjectName instanceON, ServiceRegistryWrapper depTracker, Document document, String namespace) {
         Element root = XmlUtil.createElement(document, XmlNetconfConstants.MODULE_KEY, Optional.<String>absent());
-        // Xml.addNamespaceAttr(document, root, namespace);
 
-        final String prefix = getPrefix();
-        Element typeElement = XmlUtil.createPrefixedTextElement(document, XmlUtil.createPrefixedValue(prefix, XmlNetconfConstants.TYPE_KEY), prefix,
-                moduleName, Optional.<String>of(namespace));
-        // Xml.addNamespaceAttr(document, typeElement,
-        // XMLUtil.URN_OPENDAYLIGHT_PARAMS_XML_NS_YANG_CONTROLLER_CONFIG);
+        // type belongs to config.yang namespace, but needs to be <type prefix:moduleNS>prefix:moduleName</type>
+
+        Element typeElement = XmlUtil.createTextElementWithNamespacedContent(document, XmlNetconfConstants.TYPE_KEY,
+                XmlNetconfConstants.PREFIX, namespace, moduleName);
+
         root.appendChild(typeElement);
+        // name belongs to config.yang namespace
+        String instanceName = ObjectNameUtil.getInstanceName(instanceON);
+        Element nameElement = XmlUtil.createTextElement(document, XmlNetconfConstants.NAME_KEY, instanceName, Optional.<String>absent());
 
-        Element nameElement = XmlUtil.createTextElement(document, XmlUtil.createPrefixedValue(prefix, XmlNetconfConstants.NAME_KEY),
-                ObjectNameUtil.getInstanceName(instanceON), Optional.<String>of(namespace));
-        // Xml.addNamespaceAttr(document, nameElement,
-        // XMLUtil.URN_OPENDAYLIGHT_PARAMS_XML_NS_YANG_CONTROLLER_CONFIG);
         root.appendChild(nameElement);
 
         root = instanceConfig.toXml(instanceON, depTracker, namespace, document, root);
@@ -80,10 +78,6 @@ public class ModuleConfig {
         return root;
     }
 
-    private String getPrefix() {
-        return XmlNetconfConstants.PREFIX;
-    }
-
     public ModuleElementResolved fromXml(XmlElement moduleElement, ServiceRegistryWrapper depTracker, String instanceName,
                                          String moduleNamespace, EditStrategyType defaultStrategy, Map<String, Map<Date,EditConfig.IdentityMapping>> identityMap) throws NetconfDocumentedException {
 
index eb5c018..559de7a 100644 (file)
@@ -131,11 +131,15 @@ public final class Services {
         for (String namespace : mappedServices.keySet()) {
 
             for (Entry<String, Map<String, String>> serviceEntry : mappedServices.get(namespace).entrySet()) {
+                // service belongs to config.yang namespace
                 Element serviceElement = XmlUtil.createElement(document, SERVICE_KEY, Optional.<String>absent());
                 root.appendChild(serviceElement);
 
-                Element typeElement = XmlUtil.createPrefixedTextElement(document, XmlUtil.createPrefixedValue(XmlNetconfConstants.PREFIX, TYPE_KEY), XmlNetconfConstants.PREFIX,
-                        serviceEntry.getKey(), Optional.of(namespace));
+                // type belongs to config.yang namespace
+                String serviceType = serviceEntry.getKey();
+                Element typeElement = XmlUtil.createTextElementWithNamespacedContent(document, XmlNetconfConstants.TYPE_KEY,
+                        XmlNetconfConstants.PREFIX, namespace, serviceType);
+
                 serviceElement.appendChild(typeElement);
 
                 for (Entry<String, String> instanceEntry : serviceEntry.getValue().entrySet()) {
index 2e8d1f6..f8d21e4 100644 (file)
@@ -8,11 +8,42 @@
 
 package org.opendaylight.controller.netconf.confignetconfconnector;
 
+import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.opendaylight.controller.netconf.util.test.XmlUnitUtil.assertContainsElement;
+import static org.opendaylight.controller.netconf.util.test.XmlUnitUtil.assertContainsElementWithText;
+import static org.opendaylight.controller.netconf.util.xml.XmlUtil.readXmlToElement;
+
 import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
 import com.google.common.collect.Sets;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.math.BigInteger;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import javax.management.InstanceAlreadyExistsException;
+import javax.management.InstanceNotFoundException;
+import javax.management.ObjectName;
+import javax.xml.parsers.ParserConfigurationException;
 import org.custommonkey.xmlunit.AbstractNodeTester;
 import org.custommonkey.xmlunit.NodeTest;
 import org.custommonkey.xmlunit.NodeTestException;
@@ -83,38 +114,6 @@ import org.w3c.dom.Text;
 import org.w3c.dom.traversal.DocumentTraversal;
 import org.xml.sax.SAXException;
 
-import javax.management.InstanceAlreadyExistsException;
-import javax.management.InstanceNotFoundException;
-import javax.management.ObjectName;
-import javax.xml.parsers.ParserConfigurationException;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.math.BigInteger;
-import java.net.URISyntaxException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.opendaylight.controller.netconf.util.test.XmlUnitUtil.assertContainsElement;
-import static org.opendaylight.controller.netconf.util.test.XmlUnitUtil.assertContainsElementWithText;
-import static org.opendaylight.controller.netconf.util.xml.XmlUtil.readXmlToElement;
-
 
 public class NetconfMappingTest extends AbstractConfigTest {
     private static final Logger logger = LoggerFactory.getLogger(NetconfMappingTest.class);
@@ -573,7 +572,7 @@ public class NetconfMappingTest extends AbstractConfigTest {
         String enumContent = "TWO";
 
         for (XmlElement moduleElement : modulesElement.getChildElements("module")) {
-            String name = moduleElement.getOnlyChildElement("prefix:name").getTextContent();
+            String name = moduleElement.getOnlyChildElement("name").getTextContent();
             if(name.equals(INSTANCE_NAME)) {
                 XmlElement enumAttr = moduleElement.getOnlyChildElement(enumName);
                 assertEquals(enumContent, enumAttr.getTextContent());
@@ -599,7 +598,7 @@ public class NetconfMappingTest extends AbstractConfigTest {
 
         for (XmlElement moduleElement : modulesElement.getChildElements("module")) {
             for (XmlElement type : moduleElement.getChildElements("type")) {
-                if (type.getNamespace() != null) {
+                if (type.getNamespaceOptionally().isPresent()) {
                     configAttributeType.add(type.getTextContent());
                 }
             }
index cd53995..fd43f67 100644 (file)
@@ -386,10 +386,10 @@ public class NetconfITTest extends AbstractNetconfConfigTest {
 
             NetconfMessage response = netconfClient.sendMessage(getConfig);
 
-            assertThat(XmlUtil.toString(response.getDocument()), JUnitMatchers.containsString("<prefix:afi xmlns:prefix=\"urn:opendaylight:params:xml:ns:yang:controller:config:test:types\">prefix:test-identity1</prefix:afi>"));
-            assertThat(XmlUtil.toString(response.getDocument()), JUnitMatchers.containsString("<prefix:afi xmlns:prefix=\"urn:opendaylight:params:xml:ns:yang:controller:config:test:types\">prefix:test-identity2</prefix:afi>"));
-            assertThat(XmlUtil.toString(response.getDocument()), JUnitMatchers.containsString("<prefix:safi xmlns:prefix=\"urn:opendaylight:params:xml:ns:yang:controller:config:test:types\">prefix:test-identity2</prefix:safi>"));
-            assertThat(XmlUtil.toString(response.getDocument()), JUnitMatchers.containsString("<prefix:safi xmlns:prefix=\"urn:opendaylight:params:xml:ns:yang:controller:config:test:types\">prefix:test-identity1</prefix:safi>"));
+            assertThat(XmlUtil.toString(response.getDocument()), JUnitMatchers.containsString("<afi xmlns:prefix=\"urn:opendaylight:params:xml:ns:yang:controller:config:test:types\">prefix:test-identity1</afi>"));
+            assertThat(XmlUtil.toString(response.getDocument()), JUnitMatchers.containsString("<afi xmlns:prefix=\"urn:opendaylight:params:xml:ns:yang:controller:config:test:types\">prefix:test-identity2</afi>"));
+            assertThat(XmlUtil.toString(response.getDocument()), JUnitMatchers.containsString("<safi xmlns:prefix=\"urn:opendaylight:params:xml:ns:yang:controller:config:test:types\">prefix:test-identity2</safi>"));
+            assertThat(XmlUtil.toString(response.getDocument()), JUnitMatchers.containsString("<safi xmlns:prefix=\"urn:opendaylight:params:xml:ns:yang:controller:config:test:types\">prefix:test-identity1</safi>"));
 
         } catch (Exception e) {
             fail(Throwables.getStackTraceAsString(e));
index 66603fb..ac200a0 100644 (file)
@@ -10,9 +10,17 @@ package org.opendaylight.controller.netconf.util.xml;
 
 import com.google.common.base.Optional;
 import com.google.common.base.Predicate;
+import com.google.common.base.Strings;
 import com.google.common.collect.Collections2;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import javax.annotation.Nullable;
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
 import org.opendaylight.controller.netconf.util.exception.MissingNameSpaceException;
 import org.opendaylight.controller.netconf.util.exception.UnexpectedElementException;
@@ -28,14 +36,6 @@ import org.w3c.dom.NodeList;
 import org.w3c.dom.Text;
 import org.xml.sax.SAXException;
 
-import javax.annotation.Nullable;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
 public final class XmlElement {
 
     private final Element element;
@@ -111,7 +111,7 @@ public final class XmlElement {
     public void checkNamespaceAttribute(String expectedNamespace) throws UnexpectedNamespaceException, MissingNameSpaceException {
         if (!getNamespaceAttribute().equals(expectedNamespace))
         {
-            throw new UnexpectedNamespaceException(String.format("Unexpected namespace %s for element %s, should be %s",
+            throw new UnexpectedNamespaceException(String.format("Unexpected namespace %s should be %s",
                     getNamespaceAttribute(),
                     expectedNamespace),
                     NetconfDocumentedException.ErrorType.application,
@@ -123,7 +123,7 @@ public final class XmlElement {
     public void checkNamespace(String expectedNamespace) throws UnexpectedNamespaceException, MissingNameSpaceException {
         if (!getNamespace().equals(expectedNamespace))
        {
-            throw new UnexpectedNamespaceException(String.format("Unexpected namespace %s for element %s, should be %s",
+            throw new UnexpectedNamespaceException(String.format("Unexpected namespace %s should be %s",
                     getNamespace(),
                     expectedNamespace),
                     NetconfDocumentedException.ErrorType.application,
@@ -320,23 +320,22 @@ public final class XmlElement {
     }
 
     public String getTextContent() throws NetconfDocumentedException {
-        Node textChild = element.getFirstChild();
-        if (null == textChild){
-            throw new NetconfDocumentedException(String.format( "Child node expected, got null for " + getName() + " : " + element),
-                    NetconfDocumentedException.ErrorType.application,
-                    NetconfDocumentedException.ErrorTag.invalid_value,
-                    NetconfDocumentedException.ErrorSeverity.error);
+        NodeList childNodes = element.getChildNodes();
+        if (childNodes.getLength() == 0) {
+            return "";
         }
-        if (!(textChild instanceof Text)){
-            throw new NetconfDocumentedException(String.format(getName() + " should contain text." +
-                    Text.class.getName() + " expected, got " + textChild),
-                    NetconfDocumentedException.ErrorType.application,
-                    NetconfDocumentedException.ErrorTag.invalid_value,
-                    NetconfDocumentedException.ErrorSeverity.error);
+        for(int i = 0; i < childNodes.getLength(); i++) {
+            Node textChild = childNodes.item(i);
+            if (textChild instanceof Text) {
+                String content = textChild.getTextContent();
+                return content.trim();
+            }
         }
-        String content = textChild.getTextContent();
-        // Trim needed
-        return content.trim();
+        throw new NetconfDocumentedException(getName() + " should contain text.",
+                NetconfDocumentedException.ErrorType.application,
+                NetconfDocumentedException.ErrorTag.invalid_value,
+                NetconfDocumentedException.ErrorSeverity.error
+        );
     }
 
     public String getNamespaceAttribute() throws MissingNameSpaceException {
@@ -351,15 +350,24 @@ public final class XmlElement {
         return attribute;
     }
 
-    public String getNamespace() throws MissingNameSpaceException {
+    public Optional<String> getNamespaceOptionally() {
         String namespaceURI = element.getNamespaceURI();
-        if (namespaceURI  == null || namespaceURI.equals("")){
+        if (Strings.isNullOrEmpty(namespaceURI)) {
+            return Optional.absent();
+        } else {
+            return Optional.of(namespaceURI);
+        }
+    }
+
+    public String getNamespace() throws MissingNameSpaceException {
+        Optional<String> namespaceURI = getNamespaceOptionally();
+        if (namespaceURI.isPresent() == false){
             throw new MissingNameSpaceException(String.format("No namespace defined for %s", this),
                     NetconfDocumentedException.ErrorType.application,
                     NetconfDocumentedException.ErrorTag.operation_failed,
                     NetconfDocumentedException.ErrorSeverity.error);
         }
-        return namespaceURI;
+        return namespaceURI.get();
     }
 
     @Override
index 1f81117..b2b202b 100644 (file)
@@ -10,11 +10,12 @@ package org.opendaylight.controller.netconf.util.xml;
 
 import com.google.common.base.Charsets;
 import com.google.common.base.Optional;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-import org.w3c.dom.Node;
-import org.xml.sax.SAXException;
-
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.StringWriter;
 import javax.xml.XMLConstants;
 import javax.xml.namespace.QName;
 import javax.xml.parsers.DocumentBuilder;
@@ -32,17 +33,15 @@ import javax.xml.validation.Schema;
 import javax.xml.validation.SchemaFactory;
 import javax.xml.xpath.XPathExpression;
 import javax.xml.xpath.XPathExpressionException;
-import java.io.ByteArrayInputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.StringWriter;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.xml.sax.SAXException;
 
 public final class XmlUtil {
 
     public static final String XMLNS_ATTRIBUTE_KEY = "xmlns";
-    private static final String XMLNS_URI = "http://www.w3.org/2000/xmlns/";
+    public static final String XMLNS_URI = "http://www.w3.org/2000/xmlns/";
     private static final DocumentBuilderFactory BUILDERFACTORY;
 
     static {
@@ -118,8 +117,14 @@ public final class XmlUtil {
         return typeElement;
     }
 
-    public static Element createPrefixedTextElement(Document document, String qName, String prefix, String content, Optional<String> namespace) {
-        return createTextElement(document, qName, createPrefixedValue(prefix, content), namespace);
+    public static Element createTextElementWithNamespacedContent(Document document, String qName, String prefix,
+                                                                 String namespace, String contentWithoutPrefix) {
+
+        String content = createPrefixedValue(XmlNetconfConstants.PREFIX, contentWithoutPrefix);
+        Element element = createTextElement(document, qName, content, Optional.<String>absent());
+        String prefixedNamespaceAttr = createPrefixedValue(XMLNS_ATTRIBUTE_KEY, prefix);
+        element.setAttributeNS(XMLNS_URI, prefixedNamespaceAttr, namespace);
+        return element;
     }
 
     public static String createPrefixedValue(String prefix, String value) {
index 9f24e79..1a2512f 100644 (file)
@@ -218,16 +218,6 @@ public class NeutronPortsNorthbound {
             if (portInterface.macInUse(singleton.getMacAddress())) {
                 throw new ResourceConflictException("MAC Address is in use.");
             }
-            Object[] instances = ServiceHelper.getGlobalInstances(INeutronPortAware.class, this, null);
-            if (instances != null) {
-                for (Object instance : instances) {
-                    INeutronPortAware service = (INeutronPortAware) instance;
-                    int status = service.canCreatePort(singleton);
-                    if (status < 200 || status > 299) {
-                        return Response.status(status).build();
-                    }
-                }
-            }
             /*
              * if fixed IPs are specified, each one has to have an existing subnet ID
              * that is in the same scoping network as the port.  In addition, if an IP
@@ -260,6 +250,18 @@ public class NeutronPortsNorthbound {
                 }
             }
 
+            Object[] instances = ServiceHelper.getGlobalInstances(INeutronPortAware.class, this, null);
+            if (instances != null) {
+                for (Object instance : instances) {
+                    INeutronPortAware service = (INeutronPortAware) instance;
+                    int status = service.canCreatePort(singleton);
+                    if (status < 200 || status > 299) {
+                        return Response.status(status).build();
+                    }
+                }
+            }
+
+
             // add the port to the cache
             portInterface.addPort(singleton);
             if (instances != null) {
@@ -309,15 +311,7 @@ public class NeutronPortsNorthbound {
                 if (portInterface.macInUse(test.getMacAddress())) {
                     throw new ResourceConflictException("MAC address in use");
                 }
-                if (instances != null) {
-                    for (Object instance : instances) {
-                        INeutronPortAware service = (INeutronPortAware) instance;
-                        int status = service.canCreatePort(test);
-                        if (status < 200 || status > 299) {
-                            return Response.status(status).build();
-                        }
-                    }
-                }
+
                 /*
                  * if fixed IPs are specified, each one has to have an existing subnet ID
                  * that is in the same scoping network as the port.  In addition, if an IP
@@ -351,6 +345,15 @@ public class NeutronPortsNorthbound {
                         }
                     }
                 }
+                if (instances != null) {
+                    for (Object instance : instances) {
+                        INeutronPortAware service = (INeutronPortAware) instance;
+                        int status = service.canCreatePort(test);
+                        if (status < 200 || status > 299) {
+                            return Response.status(status).build();
+                        }
+                    }
+                }
             }
 
             //once everything has passed, then we can add to the cache

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