Merge "Reenable netconf-notifications-impl xml tests"
authorTony Tkacik <ttkacik@cisco.com>
Thu, 19 Mar 2015 08:16:13 +0000 (08:16 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Thu, 19 Mar 2015 08:16:14 +0000 (08:16 +0000)
31 files changed:
features/mdsal/pom.xml
features/netconf/pom.xml
features/netconf/src/main/resources/features.xml
opendaylight/config/config-persister-feature-adapter/src/main/java/org/opendaylight/controller/configpusherfeature/internal/FeatureConfigPusher.java
opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/md/sal/dom/spi/AbstractDOMDataTreeChangeListenerRegistration.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/md/sal/dom/spi/AbstractRegistrationTree.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/md/sal/dom/spi/RegistrationTreeNode.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/md/sal/dom/spi/RegistrationTreeSnapshot.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/sal/core/spi/ForwardingConsumerSession.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/sal/core/spi/ForwardingProviderSession.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/sal/core/spi/data/AbstractDOMStoreTreeChangePublisher.java [new file with mode: 0644]
opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/InMemoryDOMDataStore.java
opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/InMemoryDOMStoreTreeChangePublisher.java [new file with mode: 0644]
opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/SimpleDataTreeCandidate.java [new file with mode: 0644]
opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/DataChangeListenerRegistrationImpl.java [new file with mode: 0644]
opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/ListenerNode.java
opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/ListenerTree.java
opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/ListenerWalker.java
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/NormalizedNodeJsonBodyWriter.java
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/NormalizedNodeXmlBodyWriter.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/osgi/NetconfOperationServiceFactoryImpl.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/osgi/YangStoreService.java
opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/netconf/mdsal/connector/MdsalNetconfOperationServiceFactory.java
opendaylight/netconf/mdsal-netconf-monitoring/src/main/java/org/opendaylight/controller/config/yang/netconf/mdsal/monitoring/NetconfMdsalMonitoringMapperModule.java
opendaylight/netconf/mdsal-netconf-monitoring/src/main/java/org/opendaylight/controller/netconf/monitoring/NetconfMonitoringOperationServiceFactory.java
opendaylight/netconf/netconf-notifications-impl/src/main/java/org/opendaylight/controller/netconf/notifications/impl/osgi/Activator.java
opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/FakeModuleBuilderCapability.java
opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/ModuleBuilderCapability.java
opendaylight/netconf/netconf-util/pom.xml
opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/capability/BasicCapability.java [new file with mode: 0644]
opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/capability/YangModuleCapability.java [new file with mode: 0644]

index bd0a99d9cae3f00373a7c9044823d913a96bfc8c..35d5dc21b394b93abf73c45ce6fe44e3dbe9ce7b 100644 (file)
           <groupId>org.opendaylight.controller</groupId>
           <artifactId>mdsal-netconf-monitoring</artifactId>
       </dependency>
-
+      <dependency>
+          <groupId>org.opendaylight.controller</groupId>
+          <artifactId>netconf-mdsal-config</artifactId>
+          <version>${netconf.version}</version>
+          <type>xml</type>
+          <classifier>config</classifier>
+      </dependency>
     <dependency>
       <groupId>org.opendaylight.controller</groupId>
       <artifactId>sal-netconf-connector</artifactId>
index b28a53b65c72a0dbf0860a0febbed3fc88c4c69f..8af370670639f461dcd5254465f7aa920cf501db 100644 (file)
       <groupId>org.opendaylight.controller</groupId>
       <artifactId>netconf-config</artifactId>
     </dependency>
-    <dependency>
-      <groupId>org.opendaylight.controller</groupId>
-      <artifactId>netconf-mdsal-config</artifactId>
-    </dependency>
     <dependency>
       <groupId>org.opendaylight.controller</groupId>
       <artifactId>netconf-auth</artifactId>
       <groupId>org.opendaylight.yangtools.model</groupId>
       <artifactId>ietf-yang-types</artifactId>
     </dependency>
+      <dependency>
+          <groupId>org.opendaylight.yangtools</groupId>
+          <artifactId>yang-model-api</artifactId>
+      </dependency>
     <dependency>
       <groupId>org.opendaylight.controller</groupId>
       <artifactId>netconf-mapping-api</artifactId>
index aa8287d70928690cd9c3f4c30247b4597f167fe4..dbd940f5e663e157409f1a57ac4fa421680572a2 100644 (file)
@@ -35,6 +35,7 @@
   </feature>
   <feature name='odl-netconf-util' version='${project.version}'>
     <feature version='${project.version}'>odl-netconf-mapping-api</feature>
+    <bundle>mvn:org.opendaylight.yangtools/yang-model-api/${yangtools.version}</bundle>
     <bundle>mvn:org.opendaylight.controller/netconf-util/${project.version}</bundle>
   </feature>
     <feature name='odl-netconf-impl' version='${project.version}' description="OpenDaylight :: Netconf :: Impl">
index 7b90580a660cac0a03a4b90c0c0f8d40a1d2eb68..2d3a011469e277ed5d72ddf63a5799f88d188352 100644 (file)
@@ -71,11 +71,16 @@ public class FeatureConfigPusher {
     private LinkedHashSet<FeatureConfigSnapshotHolder> pushConfig(final Feature feature) throws Exception, InterruptedException {
         LinkedHashSet<FeatureConfigSnapshotHolder> configs = new LinkedHashSet<FeatureConfigSnapshotHolder>();
         if(isInstalled(feature)) {
-            ChildAwareFeatureWrapper wrappedFeature = new ChildAwareFeatureWrapper(feature,featuresService);
-            configs = wrappedFeature.getFeatureConfigSnapshotHolders();
-            if(!configs.isEmpty()) {
-                configs = pushConfig(configs);
-                feature2configs.putAll(feature, configs);
+            // FIXME Workaround for BUG-2836, features service returns null for feature: standard-condition-webconsole_0_0_0, 3.0.1
+            if(featuresService.getFeature(feature.getName(), feature.getVersion()) == null) {
+                LOG.warn("Feature: {}, {} is missing from features service. Skipping", feature.getName(), feature.getVersion());
+            } else {
+                ChildAwareFeatureWrapper wrappedFeature = new ChildAwareFeatureWrapper(feature, featuresService);
+                configs = wrappedFeature.getFeatureConfigSnapshotHolders();
+                if (!configs.isEmpty()) {
+                    configs = pushConfig(configs);
+                    feature2configs.putAll(feature, configs);
+                }
             }
         }
         return configs;
diff --git a/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/md/sal/dom/spi/AbstractDOMDataTreeChangeListenerRegistration.java b/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/md/sal/dom/spi/AbstractDOMDataTreeChangeListenerRegistration.java
new file mode 100644 (file)
index 0000000..8033438
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2015 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.spi;
+
+import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeChangeListener;
+import org.opendaylight.yangtools.concepts.AbstractListenerRegistration;
+
+/**
+ * Abstract implementation of a ListenerRegistration constrained to subclasses
+ * of {@link DOMDataTreeChangeListener}.
+ *
+ * @param <T> type of listener
+ */
+public abstract class AbstractDOMDataTreeChangeListenerRegistration<T extends DOMDataTreeChangeListener> extends AbstractListenerRegistration<T> {
+    protected AbstractDOMDataTreeChangeListenerRegistration(final T listener) {
+        super(listener);
+    }
+}
diff --git a/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/md/sal/dom/spi/AbstractRegistrationTree.java b/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/md/sal/dom/spi/AbstractRegistrationTree.java
new file mode 100644 (file)
index 0000000..c1865c8
--- /dev/null
@@ -0,0 +1,100 @@
+/**
+ * Copyright (c) 2015 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.spi;
+
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+import javax.annotation.Nonnull;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+
+/**
+ * An abstract tree of registrations. Allows a read-only snapshot to be taken.
+ *
+ * @param <T> Type of registered object
+ */
+public abstract class AbstractRegistrationTree<T> {
+    private final ReadWriteLock rwLock = new ReentrantReadWriteLock(true);
+    private final RegistrationTreeNode<T> rootNode = new RegistrationTreeNode<>(null, null);
+
+    protected AbstractRegistrationTree() {
+
+    }
+
+    /**
+     * Acquire the read-write lock. This should be done before invoking {@link #findNodeFor(Iterable)}.
+     */
+    protected final void takeLock() {
+        rwLock.writeLock().lock();
+    }
+
+    /**
+     * Release the read-write lock. This should be done after invocation of {@link #findNodeFor(Iterable)}
+     * and modification of the returned node. Note that callers should do so in a finally block.
+     */
+    protected final void releaseLock() {
+        rwLock.writeLock().unlock();
+    }
+
+    /**
+     * Find an existing, or allocate a fresh, node for a particular path. Must be called with the
+     * read-write lock held.
+     *
+     * @param path Path to find a node for
+     * @return A registration node for the specified path
+     */
+    @Nonnull protected final RegistrationTreeNode<T> findNodeFor(@Nonnull final Iterable<PathArgument> path) {
+        RegistrationTreeNode<T> walkNode = rootNode;
+        for (final PathArgument arg : path) {
+            walkNode = walkNode.ensureChild(arg);
+        }
+
+        return walkNode;
+    }
+
+    /**
+     * Add a registration to a particular node. The node must have been returned via {@link #findNodeFor(Iterable)}
+     * and the lock must still be held.
+     *
+     * @param node Tree node
+     * @param registration Registration instance
+     */
+    protected final void addRegistration(@Nonnull final RegistrationTreeNode<T> node, @Nonnull final T registration) {
+        node.addRegistration(registration);
+    }
+
+    /**
+     * Remove a registration from a particular node. This method must not be called while the read-write lock
+     * is held.
+     *
+     * @param node Tree node
+     * @param registration Registration instance
+     */
+    protected final void removeRegistration(@Nonnull final RegistrationTreeNode<T> node, @Nonnull final T registration) {
+        // Take the write lock
+        rwLock.writeLock().lock();
+        try {
+            node.removeRegistration(registration);
+        } finally {
+            // Always release the lock
+            rwLock.writeLock().unlock();
+        }
+    }
+
+    /**
+     * Obtain a tree snapshot. This snapshot ensures a consistent view of
+     * registrations. The snapshot should be closed as soon as it is not required,
+     * because each unclosed instance blocks modification of this tree.
+     *
+     * @return A snapshot instance.
+     */
+    @Nonnull public final RegistrationTreeSnapshot<T> takeSnapshot() {
+        final RegistrationTreeSnapshot<T> ret = new RegistrationTreeSnapshot<>(rwLock.readLock(), rootNode);
+        rwLock.readLock().lock();
+        return ret;
+    }
+}
diff --git a/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/md/sal/dom/spi/RegistrationTreeNode.java b/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/md/sal/dom/spi/RegistrationTreeNode.java
new file mode 100644 (file)
index 0000000..41e80ea
--- /dev/null
@@ -0,0 +1,138 @@
+/**
+ * Copyright (c) 2015 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.spi;
+
+import com.google.common.base.MoreObjects;
+import com.google.common.base.Preconditions;
+import java.lang.ref.Reference;
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import javax.annotation.Nonnull;
+import org.opendaylight.yangtools.concepts.Identifiable;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This is a single node within the registration tree. Note that the data returned from
+ * and instance of this class is guaranteed to have any relevance or consistency
+ * only as long as the {@link RegistrationTreeSnapshot} instance through which it is reached
+ * remains unclosed.
+ *
+ * @param <T> registration type
+ * @author Robert Varga
+ */
+public final class RegistrationTreeNode<T> implements Identifiable<PathArgument> {
+    private static final Logger LOG = LoggerFactory.getLogger(RegistrationTreeNode.class);
+
+    private final Map<PathArgument, RegistrationTreeNode<T>> children = new HashMap<>();
+    private final Collection<T> registrations = new ArrayList<>(2);
+    private final Collection<T> publicRegistrations = Collections.unmodifiableCollection(registrations);
+    private final Reference<RegistrationTreeNode<T>> parent;
+    private final PathArgument identifier;
+
+    RegistrationTreeNode(final RegistrationTreeNode<T> parent, final PathArgument identifier) {
+        this.parent = new WeakReference<>(parent);
+        this.identifier = identifier;
+    }
+
+    @Override
+    public PathArgument getIdentifier() {
+        return identifier;
+    }
+
+    /**
+     * Return the child matching a {@link PathArgument} specification.
+     *
+     * @param arg Child identifier
+     * @return Child matching exactly, or null.
+     */
+    public RegistrationTreeNode<T> getExactChild(@Nonnull final PathArgument arg) {
+        return children.get(Preconditions.checkNotNull(arg));
+    }
+
+    /**
+     * Return a collection children which match a {@link PathArgument} specification inexactly.
+     * This explicitly excludes the child returned by {@link #getExactChild(PathArgument)}.
+     *
+     * @param arg Child identifier
+     * @return Collection of children, guaranteed to be non-null.
+     */
+    public @Nonnull Collection<RegistrationTreeNode<T>> getInexactChildren(@Nonnull final PathArgument arg) {
+        Preconditions.checkNotNull(arg);
+        if (arg instanceof NodeWithValue || arg instanceof NodeIdentifierWithPredicates) {
+            /*
+             * TODO: This just all-or-nothing wildcards, which we have historically supported. Given
+             *       that the argument is supposed to have all the elements filled out, we could support
+             *       partial wildcards by iterating over the registrations and matching the maps for
+             *       partial matches.
+             */
+            final RegistrationTreeNode<T> child = children.get(new NodeIdentifier(arg.getNodeType()));
+            if (child == null) {
+                return Collections.emptyList();
+            } else {
+                return Collections.singletonList(child);
+            }
+        } else {
+            return Collections.emptyList();
+        }
+    }
+
+    public Collection<T> getRegistrations() {
+        return publicRegistrations;
+    }
+
+    RegistrationTreeNode<T> ensureChild(@Nonnull final PathArgument child) {
+        RegistrationTreeNode<T> potential = children.get(Preconditions.checkNotNull(child));
+        if (potential == null) {
+            potential = new RegistrationTreeNode<T>(this, child);
+            children.put(child, potential);
+        }
+        return potential;
+    }
+
+    void addRegistration(@Nonnull final T registration) {
+        registrations.add(Preconditions.checkNotNull(registration));
+        LOG.debug("Registration {} added", registration);
+    }
+
+    void removeRegistration(@Nonnull final T registration) {
+        registrations.remove(Preconditions.checkNotNull(registration));
+        LOG.debug("Registration {} removed", registration);
+
+        // We have been called with the write-lock held, so we can perform some cleanup.
+        removeThisIfUnused();
+    }
+
+    private void removeThisIfUnused() {
+        final RegistrationTreeNode<T> p = parent.get();
+        if (p != null && registrations.isEmpty() && children.isEmpty()) {
+            p.removeChild(identifier);
+        }
+    }
+
+    private void removeChild(final PathArgument arg) {
+        children.remove(arg);
+        removeThisIfUnused();
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(this)
+                .add("identifier", identifier)
+                .add("registrations", registrations.size())
+                .add("children", children.size()).toString();
+    }
+}
diff --git a/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/md/sal/dom/spi/RegistrationTreeSnapshot.java b/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/md/sal/dom/spi/RegistrationTreeSnapshot.java
new file mode 100644 (file)
index 0000000..09b8b2f
--- /dev/null
@@ -0,0 +1,44 @@
+/**
+ * Copyright (c) 2015 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.spi;
+
+import com.google.common.base.Preconditions;
+import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
+import java.util.concurrent.locks.Lock;
+
+/**
+ * A stable read-only snapshot of a {@link AbstractRegistrationTree}.
+ *
+ * @author Robert Varga
+ */
+public final class RegistrationTreeSnapshot<T> implements AutoCloseable {
+    @SuppressWarnings("rawtypes")
+    private static final AtomicIntegerFieldUpdater<RegistrationTreeSnapshot> CLOSED_UPDATER = AtomicIntegerFieldUpdater.newUpdater(RegistrationTreeSnapshot.class, "closed");
+    private final RegistrationTreeNode<T> node;
+    private final Lock lock;
+
+    // Used via CLOSED_UPDATER
+    @SuppressWarnings("unused")
+    private volatile int closed = 0;
+
+    RegistrationTreeSnapshot(final Lock lock, final RegistrationTreeNode<T> node) {
+        this.lock = Preconditions.checkNotNull(lock);
+        this.node = Preconditions.checkNotNull(node);
+    }
+
+    public RegistrationTreeNode<T> getRootNode() {
+        return node;
+    }
+
+    @Override
+    public void close() {
+        if (CLOSED_UPDATER.compareAndSet(this, 0, 1)) {
+            lock.unlock();
+        }
+    }
+}
diff --git a/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/sal/core/spi/ForwardingConsumerSession.java b/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/sal/core/spi/ForwardingConsumerSession.java
new file mode 100644 (file)
index 0000000..ba14b0f
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.core.spi;
+
+import java.util.concurrent.Future;
+import org.opendaylight.controller.sal.core.api.Broker.ConsumerSession;
+import org.opendaylight.controller.sal.core.api.BrokerService;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+
+public abstract class ForwardingConsumerSession implements ConsumerSession {
+
+    protected abstract ConsumerSession delegate();
+
+    @Override
+    public void close() {
+        delegate().close();
+    }
+
+    @Override
+    public <T extends BrokerService> T getService(Class<T> arg0) {
+        return delegate().getService(arg0);
+    }
+
+    @Override
+    public boolean isClosed() {
+        return delegate().isClosed();
+    }
+
+    @Override
+    @Deprecated
+    public Future<RpcResult<CompositeNode>> rpc(QName arg0, CompositeNode arg1) {
+        return delegate().rpc(arg0, arg1);
+    }
+
+
+}
diff --git a/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/sal/core/spi/ForwardingProviderSession.java b/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/sal/core/spi/ForwardingProviderSession.java
new file mode 100644 (file)
index 0000000..d329997
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.sal.core.spi;
+
+import java.util.Set;
+import java.util.concurrent.Future;
+import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;
+import org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration;
+import org.opendaylight.controller.sal.core.api.Broker.RpcRegistration;
+import org.opendaylight.controller.sal.core.api.BrokerService;
+import org.opendaylight.controller.sal.core.api.RpcImplementation;
+import org.opendaylight.controller.sal.core.api.RpcRegistrationListener;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+
+public abstract class ForwardingProviderSession implements ProviderSession {
+
+
+    protected abstract ProviderSession delegate();
+
+    @Override
+    @Deprecated
+    public RoutedRpcRegistration addMountedRpcImplementation(QName arg0, RpcImplementation arg1) {
+        return delegate().addMountedRpcImplementation(arg0, arg1);
+    }
+
+    @Override
+    @Deprecated
+    public RoutedRpcRegistration addRoutedRpcImplementation(QName arg0, RpcImplementation arg1) {
+        return delegate().addRoutedRpcImplementation(arg0, arg1);
+    }
+
+    @Override
+    @Deprecated
+    public RpcRegistration addRpcImplementation(QName arg0, RpcImplementation arg1)
+            throws IllegalArgumentException {
+        return delegate().addRpcImplementation(arg0, arg1);
+    }
+
+    @Deprecated
+    @Override
+    public ListenerRegistration<RpcRegistrationListener> addRpcRegistrationListener(
+            RpcRegistrationListener arg0) {
+        return delegate().addRpcRegistrationListener(arg0);
+    }
+
+    @Override
+    public void close() {
+        delegate().close();
+    }
+
+    @Override
+    public <T extends BrokerService> T getService(Class<T> arg0) {
+        return delegate().getService(arg0);
+    }
+
+    @Override
+    public Set<QName> getSupportedRpcs() {
+        return delegate().getSupportedRpcs();
+    }
+
+    @Override
+    public boolean isClosed() {
+        return delegate().isClosed();
+    }
+
+    @Override
+    public Future<RpcResult<CompositeNode>> rpc(QName arg0, CompositeNode arg1) {
+        return delegate().rpc(arg0, arg1);
+    }
+
+}
diff --git a/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/sal/core/spi/data/AbstractDOMStoreTreeChangePublisher.java b/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/sal/core/spi/data/AbstractDOMStoreTreeChangePublisher.java
new file mode 100644 (file)
index 0000000..f8ac0d8
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.core.spi.data;
+
+import com.google.common.collect.ImmutableList;
+import java.util.Collection;
+import java.util.List;
+import javax.annotation.Nonnull;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeChangeListener;
+import org.opendaylight.controller.md.sal.dom.spi.AbstractDOMDataTreeChangeListenerRegistration;
+import org.opendaylight.controller.md.sal.dom.spi.AbstractRegistrationTree;
+import org.opendaylight.controller.md.sal.dom.spi.RegistrationTreeNode;
+import org.opendaylight.controller.md.sal.dom.spi.RegistrationTreeSnapshot;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidateNode;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.ModificationType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Abstract base class for {@link DOMStoreTreeChangePublisher} implementations.
+ */
+public abstract class AbstractDOMStoreTreeChangePublisher extends AbstractRegistrationTree<AbstractDOMDataTreeChangeListenerRegistration<?>> implements DOMStoreTreeChangePublisher {
+    private static final Logger LOG = LoggerFactory.getLogger(AbstractDOMStoreTreeChangePublisher.class);
+
+    /**
+     * Callback for subclass to notify specified registrations of a candidate at a specified path. This method is guaranteed
+     * to be only called from within {@link #processCandidateTree(DataTreeCandidate)}.
+     *
+     * @param registrations Registrations which are affected by the candidate node
+     * @param path Path of changed candidate node. Guaranteed to match the path specified by the registration
+     * @param node Candidate node
+     */
+    protected abstract void notifyListeners(@Nonnull Collection<AbstractDOMDataTreeChangeListenerRegistration<?>> registrations, @Nonnull YangInstanceIdentifier path, @Nonnull DataTreeCandidateNode node);
+
+    /**
+     * Callback notifying the subclass that the specified registration is being closed and it's user no longer
+     * wishes to receive notifications. This notification is invoked while the {@link ListenerRegistration#close()}
+     * method is executing. Subclasses can use this callback to properly remove any delayed notifications pending
+     * towards the registration.
+     *
+     * @param registration Registration which is being closed
+     */
+    protected abstract void registrationRemoved(@Nonnull AbstractDOMDataTreeChangeListenerRegistration<?> registration);
+
+    /**
+     * Process a candidate tree with respect to registered listeners.
+     *
+     * @param candidate candidate three which needs to be processed
+     */
+    protected final void processCandidateTree(@Nonnull final DataTreeCandidate candidate) {
+        final DataTreeCandidateNode node = candidate.getRootNode();
+        if (node.getModificationType() == ModificationType.UNMODIFIED) {
+            LOG.debug("Skipping unmodified candidate {}", candidate);
+            return;
+        }
+
+        try (final RegistrationTreeSnapshot<AbstractDOMDataTreeChangeListenerRegistration<?>> snapshot = takeSnapshot()) {
+            final List<PathArgument> toLookup = ImmutableList.copyOf(candidate.getRootPath().getPathArguments());
+            lookupAndNotify(toLookup, 0, snapshot.getRootNode(), candidate);
+        }
+    }
+
+    @Override
+    public final <L extends DOMDataTreeChangeListener> ListenerRegistration<L> registerTreeChangeListener(final YangInstanceIdentifier treeId, final L listener) {
+        // Take the write lock
+        takeLock();
+        try {
+            final RegistrationTreeNode<AbstractDOMDataTreeChangeListenerRegistration<?>> node = findNodeFor(treeId.getPathArguments());
+            final AbstractDOMDataTreeChangeListenerRegistration<L> reg = new AbstractDOMDataTreeChangeListenerRegistration<L>(listener) {
+                @Override
+                protected void removeRegistration() {
+                    AbstractDOMStoreTreeChangePublisher.this.removeRegistration(node, this);
+                    registrationRemoved(this);
+                }
+            };
+
+            addRegistration(node, reg);
+            return reg;
+        } finally {
+            // Always release the lock
+            releaseLock();
+        }
+    }
+
+    private void lookupAndNotify(final List<PathArgument> args, final int offset, final RegistrationTreeNode<AbstractDOMDataTreeChangeListenerRegistration<?>> node, final DataTreeCandidate candidate) {
+        if (args.size() != offset) {
+            final PathArgument arg = args.get(offset);
+
+            final RegistrationTreeNode<AbstractDOMDataTreeChangeListenerRegistration<?>> exactChild = node.getExactChild(arg);
+            if (exactChild != null) {
+                lookupAndNotify(args, offset + 1, exactChild, candidate);
+            }
+
+            for (RegistrationTreeNode<AbstractDOMDataTreeChangeListenerRegistration<?>> c : node.getInexactChildren(arg)) {
+                lookupAndNotify(args, offset + 1, c, candidate);
+            }
+        } else {
+            notifyNode(candidate.getRootPath(), node, candidate.getRootNode());
+        }
+    }
+
+    private void notifyNode(final YangInstanceIdentifier path, final RegistrationTreeNode<AbstractDOMDataTreeChangeListenerRegistration<?>> regNode, final DataTreeCandidateNode candNode) {
+        if (candNode.getModificationType() == ModificationType.UNMODIFIED) {
+            LOG.debug("Skipping unmodified candidate {}", path);
+            return;
+        }
+
+        final Collection<AbstractDOMDataTreeChangeListenerRegistration<?>> regs = regNode.getRegistrations();
+        if (!regs.isEmpty()) {
+            notifyListeners(regs, path, candNode);
+        }
+
+        for (DataTreeCandidateNode candChild : candNode.getChildNodes()) {
+            if (candChild.getModificationType() != ModificationType.UNMODIFIED) {
+                final RegistrationTreeNode<AbstractDOMDataTreeChangeListenerRegistration<?>> regChild = regNode.getExactChild(candChild.getIdentifier());
+                if (regChild != null) {
+                    notifyNode(path.node(candChild.getIdentifier()), regChild, candChild);
+                }
+
+                for (RegistrationTreeNode<AbstractDOMDataTreeChangeListenerRegistration<?>> rc : regNode.getInexactChildren(candChild.getIdentifier())) {
+                    notifyNode(path.node(candChild.getIdentifier()), rc, candChild);
+                }
+            }
+        }
+    }
+}
index deddd6938ae477eeebbd9fdeb50c79b6d3694eab..1f85b473feb9478f849e33fc278c7907f5530e9e 100644 (file)
@@ -19,6 +19,7 @@ import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataCh
 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeListener;
 import org.opendaylight.controller.md.sal.common.api.data.OptimisticLockFailedException;
 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeChangeListener;
 import org.opendaylight.controller.md.sal.dom.store.impl.SnapshotBackedWriteTransaction.TransactionReadyPrototype;
 import org.opendaylight.controller.md.sal.dom.store.impl.tree.ListenerTree;
 import org.opendaylight.controller.sal.core.spi.data.DOMStore;
@@ -26,6 +27,7 @@ import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadTransaction;
 import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadWriteTransaction;
 import org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCohort;
 import org.opendaylight.controller.sal.core.spi.data.DOMStoreTransactionChain;
+import org.opendaylight.controller.sal.core.spi.data.DOMStoreTreeChangePublisher;
 import org.opendaylight.controller.sal.core.spi.data.DOMStoreWriteTransaction;
 import org.opendaylight.yangtools.concepts.AbstractListenerRegistration;
 import org.opendaylight.yangtools.concepts.Identifiable;
@@ -56,7 +58,7 @@ import org.slf4j.LoggerFactory;
  * to implement {@link DOMStore} contract.
  *
  */
-public class InMemoryDOMDataStore extends TransactionReadyPrototype implements DOMStore, Identifiable<String>, SchemaContextListener, AutoCloseable {
+public class InMemoryDOMDataStore extends TransactionReadyPrototype implements DOMStore, Identifiable<String>, SchemaContextListener, AutoCloseable, DOMStoreTreeChangePublisher {
     private static final Logger LOG = LoggerFactory.getLogger(InMemoryDOMDataStore.class);
     private static final ListenableFuture<Void> SUCCESSFUL_FUTURE = Futures.immediateFuture(null);
     private static final ListenableFuture<Boolean> CAN_COMMIT_FUTURE = Futures.immediateFuture(Boolean.TRUE);
@@ -78,6 +80,7 @@ public class InMemoryDOMDataStore extends TransactionReadyPrototype implements D
     private final AtomicLong txCounter = new AtomicLong(0);
 
     private final QueuedNotificationManager<DataChangeListenerRegistration<?>, DOMImmutableDataChangeEvent> dataChangeListenerNotificationManager;
+    private final InMemoryDOMStoreTreeChangePublisher changePublisher;
     private final ExecutorService dataChangeListenerExecutor;
     private final boolean debugTransactions;
     private final String name;
@@ -98,6 +101,7 @@ public class InMemoryDOMDataStore extends TransactionReadyPrototype implements D
                 new QueuedNotificationManager<>(this.dataChangeListenerExecutor,
                         DCL_NOTIFICATION_MGR_INVOKER, maxDataChangeListenerQueueSize,
                         "DataChangeListenerQueueMgr");
+        changePublisher = new InMemoryDOMStoreTreeChangePublisher(this.dataChangeListenerExecutor, maxDataChangeListenerQueueSize);
     }
 
     public void setCloseable(final AutoCloseable closeable) {
@@ -199,6 +203,11 @@ public class InMemoryDOMDataStore extends TransactionReadyPrototype implements D
         };
     }
 
+    @Override
+    public <L extends DOMDataTreeChangeListener> ListenerRegistration<L> registerTreeChangeListener(final YangInstanceIdentifier treeId, final L listener) {
+        return changePublisher.registerTreeChangeListener(treeId, listener);
+    }
+
     @Override
     protected void transactionAborted(final SnapshotBackedWriteTransaction tx) {
         LOG.debug("Tx: {} is closed.", tx.getIdentifier());
@@ -281,6 +290,7 @@ public class InMemoryDOMDataStore extends TransactionReadyPrototype implements D
              */
             synchronized (InMemoryDOMDataStore.this) {
                 dataTree.commit(candidate);
+                changePublisher.publishChange(candidate);
                 listenerResolver.resolve(dataChangeListenerNotificationManager);
             }
 
diff --git a/opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/InMemoryDOMStoreTreeChangePublisher.java b/opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/InMemoryDOMStoreTreeChangePublisher.java
new file mode 100644 (file)
index 0000000..999fb91
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * 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;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.concurrent.ExecutorService;
+import javax.annotation.Nonnull;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeChangeListener;
+import org.opendaylight.controller.md.sal.dom.spi.AbstractDOMDataTreeChangeListenerRegistration;
+import org.opendaylight.controller.sal.core.spi.data.AbstractDOMStoreTreeChangePublisher;
+import org.opendaylight.yangtools.util.concurrent.QueuedNotificationManager;
+import org.opendaylight.yangtools.util.concurrent.QueuedNotificationManager.Invoker;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidateNode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+final class InMemoryDOMStoreTreeChangePublisher extends AbstractDOMStoreTreeChangePublisher {
+    private static final Invoker<AbstractDOMDataTreeChangeListenerRegistration<?>, DataTreeCandidate> MANAGER_INVOKER =
+            new Invoker<AbstractDOMDataTreeChangeListenerRegistration<?>, DataTreeCandidate>() {
+                @Override
+                public void invokeListener(final AbstractDOMDataTreeChangeListenerRegistration<?> listener, final DataTreeCandidate notification) {
+                    // FIXME: this is inefficient, as we could grab the entire queue for the listener and post it
+                    final DOMDataTreeChangeListener inst = listener.getInstance();
+                    if (inst != null) {
+                        inst.onDataTreeChanged(Collections.singletonList(notification));
+                    }
+                }
+            };
+    private static final Logger LOG = LoggerFactory.getLogger(InMemoryDOMStoreTreeChangePublisher.class);
+    private final QueuedNotificationManager<AbstractDOMDataTreeChangeListenerRegistration<?>, DataTreeCandidate> notificationManager;
+
+    InMemoryDOMStoreTreeChangePublisher(final ExecutorService listenerExecutor, final int maxQueueSize) {
+        notificationManager = new QueuedNotificationManager<>(listenerExecutor, MANAGER_INVOKER, maxQueueSize, "DataTreeChangeListenerQueueMgr");
+    }
+
+    @Override
+    protected void notifyListeners(final Collection<AbstractDOMDataTreeChangeListenerRegistration<?>> registrations, final YangInstanceIdentifier path, final DataTreeCandidateNode node) {
+        final DataTreeCandidate candidate = new SimpleDataTreeCandidate(path, node);
+
+        for (AbstractDOMDataTreeChangeListenerRegistration<?> reg : registrations) {
+            LOG.debug("Enqueueing candidate {} to registration {}", candidate, registrations);
+            notificationManager.submitNotification(reg, candidate);
+        }
+    }
+
+    @Override
+    protected synchronized void registrationRemoved(final AbstractDOMDataTreeChangeListenerRegistration<?> registration) {
+        LOG.debug("Closing registration {}", registration);
+
+        // FIXME: remove the queue for this registration and make sure we clear it
+    }
+
+    synchronized void publishChange(@Nonnull final DataTreeCandidate candidate) {
+        // Runs synchronized with registrationRemoved()
+        processCandidateTree(candidate);
+    }
+}
diff --git a/opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/SimpleDataTreeCandidate.java b/opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/SimpleDataTreeCandidate.java
new file mode 100644 (file)
index 0000000..701841c
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2015 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;
+
+import com.google.common.base.MoreObjects;
+import com.google.common.base.Preconditions;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidateNode;
+
+final class SimpleDataTreeCandidate implements DataTreeCandidate {
+    private final YangInstanceIdentifier rootPath;
+    private final DataTreeCandidateNode rootNode;
+
+    SimpleDataTreeCandidate(final YangInstanceIdentifier rootPath, final DataTreeCandidateNode rootNode) {
+        this.rootPath = Preconditions.checkNotNull(rootPath);
+        this.rootNode = Preconditions.checkNotNull(rootNode);
+    }
+
+    @Override
+    public DataTreeCandidateNode getRootNode() {
+        return rootNode;
+    }
+
+    @Override
+    public YangInstanceIdentifier getRootPath() {
+        return rootPath;
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(this).add("rootPath", rootPath).add("rootNode", rootNode).toString();
+    }
+}
\ No newline at end of file
diff --git a/opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/DataChangeListenerRegistrationImpl.java b/opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/DataChangeListenerRegistrationImpl.java
new file mode 100644 (file)
index 0000000..5c06b00
--- /dev/null
@@ -0,0 +1,20 @@
+/**
+ * Copyright (c) 2015 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.controller.md.sal.common.api.data.AsyncDataChangeListener;
+import org.opendaylight.controller.md.sal.dom.store.impl.DataChangeListenerRegistration;
+import org.opendaylight.yangtools.concepts.AbstractListenerRegistration;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+abstract class DataChangeListenerRegistrationImpl<T extends AsyncDataChangeListener<YangInstanceIdentifier, NormalizedNode<?, ?>>> extends AbstractListenerRegistration<T> implements DataChangeListenerRegistration<T> {
+    public DataChangeListenerRegistrationImpl(final T listener) {
+        super(listener);
+    }
+}
\ No newline at end of file
index 0aef1429c4eaa19a22c578da74dc72dc4281a99d..b8396c8a9552cb62d5c639fec702de0172a52241 100644 (file)
@@ -8,19 +8,13 @@
 package org.opendaylight.controller.md.sal.dom.store.impl.tree;
 
 import com.google.common.base.Optional;
-import java.lang.ref.Reference;
-import java.lang.ref.WeakReference;
-import java.util.ArrayList;
+import com.google.common.base.Preconditions;
 import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
+import org.opendaylight.controller.md.sal.dom.spi.RegistrationTreeNode;
 import org.opendaylight.controller.md.sal.dom.store.impl.DataChangeListenerRegistration;
-import org.opendaylight.controller.md.sal.dom.store.impl.tree.ListenerTree.DataChangeListenerRegistrationImpl;
 import org.opendaylight.yangtools.concepts.Identifiable;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
 import org.opendaylight.yangtools.yang.data.api.schema.tree.StoreTreeNode;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 /**
  * This is a single node within the listener tree. Note that the data returned from
@@ -31,27 +25,25 @@ import org.slf4j.LoggerFactory;
  * @author Robert Varga
  */
 public class ListenerNode implements StoreTreeNode<ListenerNode>, Identifiable<PathArgument> {
+    final RegistrationTreeNode<DataChangeListenerRegistration<?>> delegate;
 
-    private static final Logger LOG = LoggerFactory.getLogger(ListenerNode.class);
-
-    private final Collection<DataChangeListenerRegistration<?>> listeners = new ArrayList<>();
-    private final Map<PathArgument, ListenerNode> children = new HashMap<>();
-    private final PathArgument identifier;
-    private final Reference<ListenerNode> parent;
-
-    ListenerNode(final ListenerNode parent, final PathArgument identifier) {
-        this.parent = new WeakReference<>(parent);
-        this.identifier = identifier;
+    ListenerNode(final RegistrationTreeNode<DataChangeListenerRegistration<?>> delegate) {
+        this.delegate = Preconditions.checkNotNull(delegate);
     }
 
     @Override
     public PathArgument getIdentifier() {
-        return identifier;
+        return delegate.getIdentifier();
     }
 
     @Override
     public Optional<ListenerNode> getChild(final PathArgument child) {
-        return Optional.fromNullable(children.get(child));
+        final RegistrationTreeNode<DataChangeListenerRegistration<?>> c = delegate.getExactChild(child);
+        if (c == null) {
+            return Optional.absent();
+        }
+
+        return Optional.of(new ListenerNode(c));
     }
 
     /**
@@ -62,45 +54,21 @@ public class ListenerNode implements StoreTreeNode<ListenerNode>, Identifiable<P
      * @return the list of current listeners
      */
     public Collection<DataChangeListenerRegistration<?>> getListeners() {
-        return listeners;
+        return delegate.getRegistrations();
     }
 
-    ListenerNode ensureChild(final PathArgument child) {
-        ListenerNode potential = children.get(child);
-        if (potential == null) {
-            potential = new ListenerNode(this, child);
-            children.put(child, potential);
-        }
-        return potential;
-    }
-
-    void addListener(final DataChangeListenerRegistration<?> listener) {
-        listeners.add(listener);
-        LOG.debug("Listener {} registered", listener);
-    }
-
-    void removeListener(final DataChangeListenerRegistrationImpl<?> listener) {
-        listeners.remove(listener);
-        LOG.debug("Listener {} unregistered", listener);
-
-        // We have been called with the write-lock held, so we can perform some cleanup.
-        removeThisIfUnused();
-    }
-
-    private void removeThisIfUnused() {
-        final ListenerNode p = parent.get();
-        if (p != null && listeners.isEmpty() && children.isEmpty()) {
-            p.removeChild(identifier);
-        }
+    @Override
+    public int hashCode() {
+        return delegate.hashCode();
     }
 
-    private void removeChild(final PathArgument arg) {
-        children.remove(arg);
-        removeThisIfUnused();
+    @Override
+    public boolean equals(final Object obj) {
+        return delegate.equals(obj);
     }
 
     @Override
     public String toString() {
-        return "Node [identifier=" + identifier + ", listeners=" + listeners.size() + ", children=" + children.size() + "]";
+        return delegate.toString();
     }
 }
index dcff6439d6608b67aea81cab5882b1d72846d2c8..0909b9941d6287f26e9774716582e5395b3e1418 100644 (file)
@@ -7,18 +7,13 @@
  */
 package org.opendaylight.controller.md.sal.dom.store.impl.tree;
 
-import java.util.concurrent.locks.ReadWriteLock;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
-
 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeListener;
+import org.opendaylight.controller.md.sal.dom.spi.AbstractRegistrationTree;
+import org.opendaylight.controller.md.sal.dom.spi.RegistrationTreeNode;
 import org.opendaylight.controller.md.sal.dom.store.impl.DataChangeListenerRegistration;
-import org.opendaylight.yangtools.concepts.AbstractListenerRegistration;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 /**
  * A set of listeners organized as a tree by node to which they listen. This class
@@ -26,11 +21,7 @@ import org.slf4j.LoggerFactory;
  *
  * @author Robert Varga
  */
-public final class ListenerTree  {
-    private static final Logger LOG = LoggerFactory.getLogger(ListenerTree.class);
-    private final ReadWriteLock rwLock = new ReentrantReadWriteLock(true);
-    private final ListenerNode rootNode = new ListenerNode(null, null);
-
+public final class ListenerTree extends AbstractRegistrationTree<DataChangeListenerRegistration<?>> {
     private ListenerTree() {
         // Private to disallow direct instantiation
     }
@@ -56,15 +47,9 @@ public final class ListenerTree  {
             final L listener, final DataChangeScope scope) {
 
         // Take the write lock
-        rwLock.writeLock().lock();
-
+        takeLock();
         try {
-            ListenerNode walkNode = rootNode;
-            for (final PathArgument arg : path.getPathArguments()) {
-                walkNode = walkNode.ensureChild(arg);
-            }
-
-            final ListenerNode node = walkNode;
+            final RegistrationTreeNode<DataChangeListenerRegistration<?>> node = findNodeFor(path.getPathArguments());
             DataChangeListenerRegistration<L> reg = new DataChangeListenerRegistrationImpl<L>(listener) {
                 @Override
                 public DataChangeScope getScope() {
@@ -88,23 +73,15 @@ public final class ListenerTree  {
                      *       While this does not directly violate the ListenerRegistration
                      *       contract, it is probably not going to be liked by the users.
                      */
-
-                    // Take the write lock
-                    ListenerTree.this.rwLock.writeLock().lock();
-                    try {
-                        node.removeListener(this);
-                    } finally {
-                        // Always release the lock
-                        ListenerTree.this.rwLock.writeLock().unlock();
-                    }
+                    ListenerTree.this.removeRegistration(node, this);
                 }
             };
 
-            node.addListener(reg);
+            addRegistration(node, reg);
             return reg;
         } finally {
             // Always release the lock
-            rwLock.writeLock().unlock();
+            releaseLock();
         }
     }
 
@@ -125,15 +102,6 @@ public final class ListenerTree  {
          *       external user exist, make the Walker a phantom reference, which
          *       will cleanup the lock if not told to do so.
          */
-        final ListenerWalker ret = new ListenerWalker(rwLock.readLock(), rootNode);
-        rwLock.readLock().lock();
-        return ret;
-    }
-
-    abstract static class DataChangeListenerRegistrationImpl<T extends AsyncDataChangeListener<YangInstanceIdentifier, NormalizedNode<?, ?>>> extends AbstractListenerRegistration<T> //
-    implements DataChangeListenerRegistration<T> {
-        public DataChangeListenerRegistrationImpl(final T listener) {
-            super(listener);
-        }
+        return new ListenerWalker(takeSnapshot());
     }
 }
index 0c297a2e2b5091c39c5c85784291c21fc7bb3cab..d1c4eacdf6e0fb29c25f63f380dad1de38fa8d10 100644 (file)
@@ -8,8 +8,8 @@
 package org.opendaylight.controller.md.sal.dom.store.impl.tree;
 
 import com.google.common.base.Preconditions;
-import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
-import java.util.concurrent.locks.Lock;
+import org.opendaylight.controller.md.sal.dom.spi.RegistrationTreeSnapshot;
+import org.opendaylight.controller.md.sal.dom.store.impl.DataChangeListenerRegistration;
 
 /**
  * A walking context, pretty much equivalent to an iterator, but it
@@ -18,27 +18,18 @@ import java.util.concurrent.locks.Lock;
  * @author Robert Varga
  */
 public class ListenerWalker implements AutoCloseable {
-    private static final AtomicIntegerFieldUpdater<ListenerWalker> CLOSED_UPDATER = AtomicIntegerFieldUpdater.newUpdater(ListenerWalker.class, "closed");
-    private final Lock lock;
-    private final ListenerNode node;
+    private final RegistrationTreeSnapshot<DataChangeListenerRegistration<?>> delegate;
 
-    // Used via CLOSED_UPDATER
-    @SuppressWarnings("unused")
-    private volatile int closed = 0;
-
-    ListenerWalker(final Lock lock, final ListenerNode node) {
-        this.lock = Preconditions.checkNotNull(lock);
-        this.node = Preconditions.checkNotNull(node);
+    ListenerWalker(final RegistrationTreeSnapshot<DataChangeListenerRegistration<?>> delegate) {
+        this.delegate = Preconditions.checkNotNull(delegate);
     }
 
     public ListenerNode getRootNode() {
-        return node;
+        return new ListenerNode(delegate.getRootNode());
     }
 
     @Override
     public void close() {
-        if (CLOSED_UPDATER.compareAndSet(this, 0, 1)) {
-            lock.unlock();
-        }
+        delegate.close();
     }
 }
\ No newline at end of file
index 4944d96b546933c49637fbb66b4b91ea8add05d1..5c17f2a14ab2558c4acd089e224828a9248530eb 100644 (file)
@@ -66,36 +66,54 @@ public class NormalizedNodeJsonBodyWriter implements MessageBodyWriter<Normalize
             return;
         }
 
+        @SuppressWarnings("unchecked")
         final InstanceIdentifierContext<SchemaNode> context = (InstanceIdentifierContext<SchemaNode>) t.getInstanceIdentifierContext();
 
         SchemaPath path = context.getSchemaNode().getPath();
-        boolean isDataRoot = false;
+        final JsonWriter jsonWriter = createJsonWriter(entityStream);
+        jsonWriter.beginObject();
+        writeNormalizedNode(jsonWriter,path,context,data);
+        jsonWriter.endObject();
+        jsonWriter.flush();
+    }
+
+    private void writeNormalizedNode(JsonWriter jsonWriter, SchemaPath path,
+            InstanceIdentifierContext<SchemaNode> context, NormalizedNode<?, ?> data) throws IOException {
+        final NormalizedNodeWriter nnWriter;
         if (SchemaPath.ROOT.equals(path)) {
-            isDataRoot = true;
+            /*
+             *  Creates writer without initialNs and we write children of root data container
+             *  which is not visible in restconf
+             */
+            nnWriter = createNormalizedNodeWriter(context,path,jsonWriter);
+            writeChildren(nnWriter,(ContainerNode) data);
         } else if (context.getSchemaNode() instanceof RpcDefinition) {
-            isDataRoot = true;
+            /*
+             *  RpcDefinition is not supported as initial codec in JSONStreamWriter,
+             *  so we need to emit initial output declaratation..
+             */
             path = ((RpcDefinition) context.getSchemaNode()).getOutput().getPath();
+            nnWriter = createNormalizedNodeWriter(context,path,jsonWriter);
+            jsonWriter.name("output");
+            jsonWriter.beginObject();
+            writeChildren(nnWriter, (ContainerNode) data);
+            jsonWriter.endObject();
         } else {
             path = path.getParent();
-            // FIXME: Add proper handling of reading root.
-        }
 
-        final JsonWriter jsonWriter = createJsonWriter(entityStream);
-        final NormalizedNodeWriter nnWriter = createNormalizedNodeWriter(context,path,jsonWriter);
-
-        jsonWriter.beginObject();
-        if(isDataRoot) {
-            writeDataRoot(nnWriter,(ContainerNode) data);
-        } else {
             if(data instanceof MapEntryNode) {
                 data = ImmutableNodes.mapNodeBuilder(data.getNodeType()).withChild(((MapEntryNode) data)).build();
             }
+            nnWriter = createNormalizedNodeWriter(context,path,jsonWriter);
             nnWriter.write(data);
         }
-
         nnWriter.flush();
-        jsonWriter.endObject();
-        jsonWriter.flush();
+    }
+
+    private void writeChildren(final NormalizedNodeWriter nnWriter, final ContainerNode data) throws IOException {
+        for(final DataContainerChild<? extends PathArgument, ?> child : data.getValue()) {
+            nnWriter.write(child);
+        }
     }
 
     private NormalizedNodeWriter createNormalizedNodeWriter(final InstanceIdentifierContext<SchemaNode> context,
@@ -104,9 +122,15 @@ public class NormalizedNodeJsonBodyWriter implements MessageBodyWriter<Normalize
         final SchemaNode schema = context.getSchemaNode();
         final JSONCodecFactory codecs = getCodecFactory(context);
 
-        URI initialNs = null;
-        if ( ! (schema instanceof RpcDefinition) && (!((DataSchemaNode)schema).isAugmenting() && !(schema instanceof SchemaContext))) {
+        final URI initialNs;
+        if ((schema instanceof DataSchemaNode)
+                && !((DataSchemaNode)schema).isAugmenting()
+                && !(schema instanceof SchemaContext)) {
+            initialNs = schema.getQName().getNamespace();
+        } else if (schema instanceof RpcDefinition) {
             initialNs = schema.getQName().getNamespace();
+        } else {
+            initialNs = null;
         }
         final NormalizedNodeStreamWriter streamWriter = JSONNormalizedNodeStreamWriter.createNestedWriter(codecs,path,initialNs,jsonWriter);
         return NormalizedNodeWriter.forStreamWriter(streamWriter);
@@ -118,15 +142,9 @@ public class NormalizedNodeJsonBodyWriter implements MessageBodyWriter<Normalize
 
     }
 
-    private JSONCodecFactory getCodecFactory(final InstanceIdentifierContext context) {
+    private JSONCodecFactory getCodecFactory(final InstanceIdentifierContext<?> context) {
         // TODO: Performance: Cache JSON Codec factory and schema context
         return JSONCodecFactory.create(context.getSchemaContext());
     }
 
-    private void writeDataRoot(final NormalizedNodeWriter nnWriter, final ContainerNode data) throws IOException {
-        for(final DataContainerChild<? extends PathArgument, ?> child : data.getValue()) {
-            nnWriter.write(child);
-        }
-    }
-
 }
index f61ec4e1c0941abef0fee706962b6a732af9c858..f6b7027b34a9994d43c2d731a40a11bcf7551bb6 100644 (file)
@@ -18,6 +18,7 @@ import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.MultivaluedMap;
 import javax.ws.rs.ext.MessageBodyWriter;
 import javax.ws.rs.ext.Provider;
+import javax.xml.XMLConstants;
 import javax.xml.stream.FactoryConfigurationError;
 import javax.xml.stream.XMLOutputFactory;
 import javax.xml.stream.XMLStreamException;
@@ -27,9 +28,7 @@ import org.opendaylight.controller.sal.rest.api.RestconfService;
 import org.opendaylight.controller.sal.restconf.impl.InstanceIdentifierContext;
 import org.opendaylight.controller.sal.restconf.impl.NormalizedNodeContext;
 import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
-import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
 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.stream.NormalizedNodeStreamWriter;
@@ -85,38 +84,45 @@ public class NormalizedNodeXmlBodyWriter implements MessageBodyWriter<Normalized
         NormalizedNode<?, ?> data = t.getData();
         SchemaPath schemaPath = pathContext.getSchemaNode().getPath();
 
-        boolean isDataRoot = false;
+
+
+        writeNormalizedNode(xmlWriter,schemaPath,pathContext,data);
+    }
+
+    private void writeNormalizedNode(XMLStreamWriter xmlWriter, SchemaPath schemaPath,InstanceIdentifierContext<?> pathContext, NormalizedNode<?, ?> data) throws IOException {
+        final NormalizedNodeWriter nnWriter;
+        final SchemaContext schemaCtx = pathContext.getSchemaContext();
         if (SchemaPath.ROOT.equals(schemaPath)) {
-            isDataRoot = true;
+            nnWriter = createNormalizedNodeWriter(xmlWriter, schemaCtx, schemaPath);
+            writeElements(xmlWriter, nnWriter, (ContainerNode) data);
         }  else if (pathContext.getSchemaNode() instanceof RpcDefinition) {
-            isDataRoot = true;
-            schemaPath = ((RpcDefinition) pathContext.getSchemaNode()).getOutput().getPath();
-        } else {
-            schemaPath = schemaPath.getParent();
-        }
-
-        final NormalizedNodeStreamWriter jsonWriter = XMLStreamNormalizedNodeStreamWriter.create(xmlWriter,
-                pathContext.getSchemaContext(), schemaPath);
-        final NormalizedNodeWriter nnWriter = NormalizedNodeWriter.forStreamWriter(jsonWriter);
-        if (isDataRoot) {
-            writeRootElement(xmlWriter, nnWriter, (ContainerNode) data);
+            nnWriter = createNormalizedNodeWriter(xmlWriter, schemaCtx, ((RpcDefinition) pathContext.getSchemaNode()).getOutput().getPath());
+            writeElements(xmlWriter, nnWriter, (ContainerNode) data);
         } else {
+            nnWriter = createNormalizedNodeWriter(xmlWriter, schemaCtx, schemaPath.getParent());
             if (data instanceof MapEntryNode) {
                 // Restconf allows returning one list item. We need to wrap it
                 // in map node in order to serialize it properly
                 data = ImmutableNodes.mapNodeBuilder(data.getNodeType()).addChild((MapEntryNode) data).build();
             }
             nnWriter.write(data);
-            nnWriter.flush();
         }
+        nnWriter.flush();
+    }
+
+    private NormalizedNodeWriter createNormalizedNodeWriter(XMLStreamWriter xmlWriter,
+            SchemaContext schemaContext, SchemaPath schemaPath) {
+        NormalizedNodeStreamWriter xmlStreamWriter = XMLStreamNormalizedNodeStreamWriter.create(xmlWriter, schemaContext, schemaPath);
+        return NormalizedNodeWriter.forStreamWriter(xmlStreamWriter);
     }
 
-    private void writeRootElement(final XMLStreamWriter xmlWriter, final NormalizedNodeWriter nnWriter, final ContainerNode data)
+    private void writeElements(final XMLStreamWriter xmlWriter, final NormalizedNodeWriter nnWriter, final ContainerNode data)
             throws IOException {
         try {
-            final QName name = SchemaContext.NAME;
-            xmlWriter.writeStartElement(name.getNamespace().toString(), name.getLocalName());
-            for (final DataContainerChild<? extends PathArgument, ?> child : data.getValue()) {
+            final QName name = data.getNodeType();
+            xmlWriter.writeStartElement(XMLConstants.DEFAULT_NS_PREFIX, name.getLocalName(), name.getNamespace().toString());
+            xmlWriter.writeDefaultNamespace(name.getNamespace().toString());
+            for(NormalizedNode<?,?> child : data.getValue()) {
                 nnWriter.write(child);
             }
             nnWriter.flush();
index 590f4c4ceb038b2a70f72c2379d5e759bc285db6..cb9c956b90c8e10bba8283bd75eabe979cb9d068 100644 (file)
@@ -8,18 +8,16 @@
 
 package org.opendaylight.controller.netconf.confignetconfconnector.osgi;
 
-import com.google.common.base.Optional;
 import java.lang.management.ManagementFactory;
-import java.util.Collection;
-import java.util.Collections;
 import java.util.HashSet;
 import java.util.Set;
 import javax.management.MBeanServer;
 import org.opendaylight.controller.config.util.ConfigRegistryJMXClient;
 import org.opendaylight.controller.netconf.api.Capability;
 import org.opendaylight.controller.netconf.api.monitoring.CapabilityListener;
-import org.opendaylight.controller.netconf.confignetconfconnector.util.Util;
 import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactory;
+import org.opendaylight.controller.netconf.util.capability.BasicCapability;
+import org.opendaylight.controller.netconf.util.capability.YangModuleCapability;
 import org.opendaylight.yangtools.yang.model.api.Module;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -100,94 +98,10 @@ public class NetconfOperationServiceFactoryImpl implements NetconfOperationServi
 
         Set<Module> modules = yangStoreSnapshot.getModules();
         for (Module module : modules) {
-            capabilities.add(new YangStoreCapability(module, yangStoreSnapshot.getModuleSource(module)));
+            capabilities.add(new YangModuleCapability(module, yangStoreSnapshot.getModuleSource(module)));
         }
 
         return capabilities;
     }
 
-    private static class BasicCapability implements Capability {
-
-        private final String capability;
-
-        private BasicCapability(final String capability) {
-            this.capability = capability;
-        }
-
-        @Override
-        public String getCapabilityUri() {
-            return capability;
-        }
-
-        @Override
-        public Optional<String> getModuleNamespace() {
-            return Optional.absent();
-        }
-
-        @Override
-        public Optional<String> getModuleName() {
-            return Optional.absent();
-        }
-
-        @Override
-        public Optional<String> getRevision() {
-            return Optional.absent();
-        }
-
-        @Override
-        public Optional<String> getCapabilitySchema() {
-            return Optional.absent();
-        }
-
-        @Override
-        public Collection<String> getLocation() {
-            return Collections.emptyList();
-        }
-
-        @Override
-        public String toString() {
-            return capability;
-        }
-    }
-
-    static final class YangStoreCapability extends BasicCapability {
-
-        private final String content;
-        private final String revision;
-        private final String moduleName;
-        private final String moduleNamespace;
-
-        public YangStoreCapability(final Module module, final String moduleContent) {
-            super(toCapabilityURI(module));
-            this.content = moduleContent;
-            this.moduleName = module.getName();
-            this.moduleNamespace = module.getNamespace().toString();
-            this.revision = Util.writeDate(module.getRevision());
-        }
-
-        @Override
-        public Optional<String> getCapabilitySchema() {
-            return Optional.of(content);
-        }
-
-        private static String toCapabilityURI(final Module module) {
-            return String.valueOf(module.getNamespace()) + "?module="
-                    + module.getName() + "&revision=" + Util.writeDate(module.getRevision());
-        }
-
-        @Override
-        public Optional<String> getModuleName() {
-            return Optional.of(moduleName);
-        }
-
-        @Override
-        public Optional<String> getModuleNamespace() {
-            return Optional.of(moduleNamespace);
-        }
-
-        @Override
-        public Optional<String> getRevision() {
-            return Optional.of(revision);
-        }
-    }
 }
index 176800fb975ba2dd7dc7fe05ad0ca03ffb301a3b..cb035161b4b2fb21388edcdaa2a857d257d52aca 100644 (file)
@@ -27,6 +27,7 @@ import org.opendaylight.controller.netconf.api.monitoring.CapabilityListener;
 import org.opendaylight.controller.netconf.notifications.BaseNetconfNotificationListener;
 import org.opendaylight.controller.netconf.notifications.BaseNotificationPublisherRegistration;
 import org.opendaylight.controller.netconf.notifications.NetconfNotificationCollector;
+import org.opendaylight.controller.netconf.util.capability.YangModuleCapability;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.notifications.rev120206.NetconfCapabilityChange;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.notifications.rev120206.NetconfCapabilityChangeBuilder;
@@ -154,7 +155,7 @@ public class YangStoreService implements YangStoreContext {
     private static final Function<Module, Capability> MODULE_TO_CAPABILITY = new Function<Module, Capability>() {
         @Override
         public Capability apply(final Module module) {
-            return new NetconfOperationServiceFactoryImpl.YangStoreCapability(module, module.getSource());
+            return new YangModuleCapability(module, module.getSource());
         }
     };
 
@@ -191,7 +192,7 @@ public class YangStoreService implements YangStoreContext {
     private static final Function<Module, Uri> MODULE_TO_URI = new Function<Module, Uri>() {
         @Override
         public Uri apply(final Module input) {
-            return new Uri(new NetconfOperationServiceFactoryImpl.YangStoreCapability(input, input.getSource()).getCapabilityUri());
+            return new Uri(new YangModuleCapability(input, input.getSource()).getCapabilityUri());
         }
     };
 
index ebb0e9d3d1ac2d9bf364afcb236e151ebecb8af2..89ce149e12f75d2f2c63dbd70aa823e95ce6b324 100644 (file)
@@ -8,18 +8,16 @@
 
 package org.opendaylight.controller.netconf.mdsal.connector;
 
-import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
-import java.util.Collection;
-import java.util.Collections;
 import java.util.HashSet;
 import java.util.Set;
 import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
 import org.opendaylight.controller.netconf.api.Capability;
 import org.opendaylight.controller.netconf.api.monitoring.CapabilityListener;
 import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactory;
+import org.opendaylight.controller.netconf.util.capability.BasicCapability;
+import org.opendaylight.controller.netconf.util.capability.YangModuleCapability;
 import org.opendaylight.controller.sal.core.api.model.SchemaService;
-import org.opendaylight.yangtools.yang.common.SimpleDateFormatUtil;
 import org.opendaylight.yangtools.yang.model.api.Module;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 import org.slf4j.Logger;
@@ -61,7 +59,7 @@ public class MdsalNetconfOperationServiceFactory implements NetconfOperationServ
         final Set<Module> modules = currentContext.getModules();
         for (final Module module : modules) {
             if(currentContext.getModuleSource(module).isPresent()) {
-                capabilities.add(new YangStoreCapability(module, currentContext.getModuleSource(module).get()));
+                capabilities.add(new YangModuleCapability(module, currentContext.getModuleSource(module).get()));
             } else {
                 LOG.warn("Missing source for module {}. This module will not be available from netconf server",
                         module);
@@ -76,88 +74,4 @@ public class MdsalNetconfOperationServiceFactory implements NetconfOperationServ
         return currentSchemaContext.registerCapabilityListener(listener);
     }
 
-    private static class BasicCapability implements Capability {
-
-        private final String capability;
-
-        private BasicCapability(final String capability) {
-            this.capability = capability;
-        }
-
-        @Override
-        public String getCapabilityUri() {
-            return capability;
-        }
-
-        @Override
-        public Optional<String> getModuleNamespace() {
-            return Optional.absent();
-        }
-
-        @Override
-        public Optional<String> getModuleName() {
-            return Optional.absent();
-        }
-
-        @Override
-        public Optional<String> getRevision() {
-            return Optional.absent();
-        }
-
-        @Override
-        public Optional<String> getCapabilitySchema() {
-            return Optional.absent();
-        }
-
-        @Override
-        public Collection<String> getLocation() {
-            return Collections.emptyList();
-        }
-
-        @Override
-        public String toString() {
-            return capability;
-        }
-    }
-
-    private static final class YangStoreCapability extends BasicCapability {
-
-        private final String content;
-        private final String revision;
-        private final String moduleName;
-        private final String moduleNamespace;
-
-        public YangStoreCapability(final Module module, final String moduleContent) {
-            super(toCapabilityURI(module));
-            this.content = moduleContent;
-            this.moduleName = module.getName();
-            this.moduleNamespace = module.getNamespace().toString();
-            this.revision = SimpleDateFormatUtil.getRevisionFormat().format(module.getRevision());
-        }
-
-        @Override
-        public Optional<String> getCapabilitySchema() {
-            return Optional.of(content);
-        }
-
-        private static String toCapabilityURI(final Module module) {
-            return String.valueOf(module.getNamespace()) + "?module="
-                    + module.getName() + "&revision=" + SimpleDateFormatUtil.getRevisionFormat().format(module.getRevision());
-        }
-
-        @Override
-        public Optional<String> getModuleName() {
-            return Optional.of(moduleName);
-        }
-
-        @Override
-        public Optional<String> getModuleNamespace() {
-            return Optional.of(moduleNamespace);
-        }
-
-        @Override
-        public Optional<String> getRevision() {
-            return Optional.of(revision);
-        }
-    }
 }
index dadc0f493b26fad16893ccf73193868d781ccfd2..3c73c2c84c5f893b9058bb123033c3be9869a633 100644 (file)
@@ -1,11 +1,6 @@
 package org.opendaylight.controller.config.yang.netconf.mdsal.monitoring;
 
-import com.google.common.base.Optional;
-import com.google.common.collect.Sets;
-import java.util.ArrayList;
-import java.util.Collection;
 import java.util.Collections;
-import java.util.List;
 import java.util.Set;
 import org.opendaylight.controller.netconf.api.Capability;
 import org.opendaylight.controller.netconf.api.monitoring.CapabilityListener;
@@ -14,7 +9,6 @@ import org.opendaylight.controller.netconf.mapping.api.NetconfOperation;
 import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService;
 import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactory;
 import org.opendaylight.controller.netconf.monitoring.GetSchema;
-import org.opendaylight.controller.netconf.monitoring.MonitoringConstants;
 
 public class NetconfMdsalMonitoringMapperModule extends org.opendaylight.controller.config.yang.netconf.mdsal.monitoring.AbstractNetconfMdsalMonitoringMapperModule {
     public NetconfMdsalMonitoringMapperModule(final org.opendaylight.controller.config.api.ModuleIdentifier identifier, final org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
@@ -56,39 +50,6 @@ public class NetconfMdsalMonitoringMapperModule extends org.opendaylight.control
 
         private final NetconfOperationService operationService;
 
-        private static final Set<Capability> CAPABILITIES = Sets.<Capability>newHashSet(new Capability() {
-
-            @Override
-            public String getCapabilityUri() {
-                return MonitoringConstants.URI;
-            }
-
-            @Override
-            public Optional<String> getModuleNamespace() {
-                return Optional.of(MonitoringConstants.NAMESPACE);
-            }
-
-            @Override
-            public Optional<String> getModuleName() {
-                return Optional.of(MonitoringConstants.MODULE_NAME);
-            }
-
-            @Override
-            public Optional<String> getRevision() {
-                return Optional.of(MonitoringConstants.MODULE_REVISION);
-            }
-
-            @Override
-            public Optional<String> getCapabilitySchema() {
-                return Optional.absent();
-            }
-
-            @Override
-            public Collection<String> getLocation() {
-                return Collections.emptyList();
-            }
-        });
-
         private static final AutoCloseable AUTO_CLOSEABLE = new AutoCloseable() {
             @Override
             public void close() throws Exception {
@@ -96,8 +57,6 @@ public class NetconfMdsalMonitoringMapperModule extends org.opendaylight.control
             }
         };
 
-        private final List<CapabilityListener> listeners = new ArrayList<>();
-
         public MdSalMonitoringMapperFactory(final NetconfOperationService operationService) {
             this.operationService = operationService;
         }
@@ -109,22 +68,19 @@ public class NetconfMdsalMonitoringMapperModule extends org.opendaylight.control
 
         @Override
         public Set<Capability> getCapabilities() {
-            return CAPABILITIES;
+            // TODO
+            // No capabilities exposed to prevent clashes with schemas from mdsal-netconf-connector (it exposes all the schemas)
+            // If the schemas exposed by mdsal-netconf-connector are filtered, this class would expose monitoring related models
+            return Collections.emptySet();
         }
 
         @Override
         public AutoCloseable registerCapabilityListener(final CapabilityListener listener) {
-            listener.onCapabilitiesAdded(getCapabilities());
-            listeners.add(listener);
             return AUTO_CLOSEABLE;
         }
 
         @Override
-        public void close() {
-            for (final CapabilityListener listener : listeners) {
-                listener.onCapabilitiesRemoved(getCapabilities());
-            }
-        }
+        public void close() {}
     }
 
 
index 78c23688e4a019b96964e531cb261dec38d465a2..cac15044f0fe0b57dd45dec7d14b8e7f89539e48 100644 (file)
@@ -8,58 +8,17 @@
 
 package org.opendaylight.controller.netconf.monitoring;
 
-import com.google.common.base.Optional;
-import com.google.common.collect.Sets;
-import java.util.ArrayList;
-import java.util.Collection;
 import java.util.Collections;
-import java.util.List;
 import java.util.Set;
 import org.opendaylight.controller.netconf.api.Capability;
 import org.opendaylight.controller.netconf.api.monitoring.CapabilityListener;
 import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService;
 import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactory;
 
-/**
-* Created by mmarsale on 18.2.2015.
-*/
 public class NetconfMonitoringOperationServiceFactory implements NetconfOperationServiceFactory, AutoCloseable {
 
     private final NetconfMonitoringOperationService operationService;
 
-    private static final Set<Capability> CAPABILITIES = Sets.<Capability>newHashSet(new Capability() {
-
-        @Override
-        public String getCapabilityUri() {
-            return MonitoringConstants.URI;
-        }
-
-        @Override
-        public Optional<String> getModuleNamespace() {
-            return Optional.of(MonitoringConstants.NAMESPACE);
-        }
-
-        @Override
-        public Optional<String> getModuleName() {
-            return Optional.of(MonitoringConstants.MODULE_NAME);
-        }
-
-        @Override
-        public Optional<String> getRevision() {
-            return Optional.of(MonitoringConstants.MODULE_REVISION);
-        }
-
-        @Override
-        public Optional<String> getCapabilitySchema() {
-            return Optional.absent();
-        }
-
-        @Override
-        public Collection<String> getLocation() {
-            return Collections.emptyList();
-        }
-    });
-
     private static final AutoCloseable AUTO_CLOSEABLE = new AutoCloseable() {
         @Override
         public void close() throws Exception {
@@ -67,8 +26,6 @@ public class NetconfMonitoringOperationServiceFactory implements NetconfOperatio
         }
     };
 
-    private final List<CapabilityListener> listeners = new ArrayList<>();
-
     public NetconfMonitoringOperationServiceFactory(final NetconfMonitoringOperationService operationService) {
         this.operationService = operationService;
     }
@@ -80,20 +37,17 @@ public class NetconfMonitoringOperationServiceFactory implements NetconfOperatio
 
     @Override
     public Set<Capability> getCapabilities() {
-        return CAPABILITIES;
+        // TODO
+        // No capabilities exposed to prevent clashes with schemas from config-netconf-connector (it exposes all the schemas)
+        // If the schemas exposed by config-netconf-connector are filtered, this class would expose monitoring related models
+        return Collections.emptySet();
     }
 
     @Override
     public AutoCloseable registerCapabilityListener(final CapabilityListener listener) {
-        listener.onCapabilitiesAdded(getCapabilities());
-        listeners.add(listener);
         return AUTO_CLOSEABLE;
     }
 
     @Override
-    public void close() {
-        for (final CapabilityListener listener : listeners) {
-            listener.onCapabilitiesRemoved(getCapabilities());
-        }
-    }
+    public void close() {}
 }
index a0a0dfcb8f5e506071daa1b5b894aa0074f556ca..64442f743d576a55f39146ed80570443c450b51b 100644 (file)
@@ -8,9 +8,7 @@
 
 package org.opendaylight.controller.netconf.notifications.impl.osgi;
 
-import com.google.common.base.Optional;
 import com.google.common.collect.Sets;
-import java.util.Collection;
 import java.util.Collections;
 import java.util.Dictionary;
 import java.util.Hashtable;
@@ -26,6 +24,7 @@ import org.opendaylight.controller.netconf.notifications.NetconfNotificationColl
 import org.opendaylight.controller.netconf.notifications.impl.NetconfNotificationManager;
 import org.opendaylight.controller.netconf.notifications.impl.ops.CreateSubscription;
 import org.opendaylight.controller.netconf.notifications.impl.ops.Get;
+import org.opendaylight.controller.netconf.util.capability.BasicCapability;
 import org.osgi.framework.BundleActivator;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.ServiceRegistration;
@@ -43,7 +42,7 @@ public class Activator implements BundleActivator {
 
         final NetconfOperationServiceFactory netconfOperationServiceFactory = new NetconfOperationServiceFactory() {
 
-            private final Set<Capability> capabilities = Collections.<Capability>singleton(new NotificationsCapability());
+            private final Set<Capability> capabilities = Collections.<Capability>singleton(new BasicCapability(NetconfNotification.NOTIFICATION_NAMESPACE));
 
             @Override
             public Set<Capability> getCapabilities() {
@@ -103,36 +102,4 @@ public class Activator implements BundleActivator {
             operationaServiceRegistration = null;
         }
     }
-
-    private class NotificationsCapability implements Capability {
-        @Override
-        public String getCapabilityUri() {
-            return NetconfNotification.NOTIFICATION_NAMESPACE;
-        }
-
-        @Override
-        public Optional<String> getModuleNamespace() {
-            return Optional.absent();
-        }
-
-        @Override
-        public Optional<String> getModuleName() {
-            return Optional.absent();
-        }
-
-        @Override
-        public Optional<String> getRevision() {
-            return Optional.absent();
-        }
-
-        @Override
-        public Optional<String> getCapabilitySchema() {
-            return Optional.absent();
-        }
-
-        @Override
-        public Collection<String> getLocation() {
-            return Collections.emptyList();
-        }
-    }
 }
index 5f8107ccb19e1bc1c490d34b04a71911eac007f2..b397bcb4c488aaf731285f6136d17b8feb9a241a 100644 (file)
@@ -9,53 +9,16 @@
 package org.opendaylight.controller.netconf.test.tool;
 
 import com.google.common.base.Optional;
-import java.util.Collections;
-import java.util.Date;
-import java.util.List;
-import org.opendaylight.controller.netconf.api.Capability;
-import org.opendaylight.controller.netconf.confignetconfconnector.util.Util;
-import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.parser.builder.impl.ModuleBuilder;
 
 /**
  * Can be passed instead of ModuleBuilderCapability when building capabilities
  * in NetconfDeviceSimulator when testing various schema resolution related exceptions.
  */
-public class FakeModuleBuilderCapability implements Capability{
-    private static final Date NO_REVISION = new Date(0);
-    private static final List<String> NETCONF = Collections.singletonList("NETCONF");
-    private final ModuleBuilder input;
-    private final Optional<String> content;
+public class FakeModuleBuilderCapability extends ModuleBuilderCapability {
 
     public FakeModuleBuilderCapability(final ModuleBuilder input, final String inputStream) {
-        this.input = input;
-        this.content = Optional.of(inputStream);
-    }
-
-    @Override
-    public String getCapabilityUri() {
-        // FIXME capabilities in Netconf-impl need to check for NO REVISION
-        final String withoutRevision = getModuleNamespace().get() + "?module=" + getModuleName().get();
-        return hasRevision() ? withoutRevision + "&revision=" + Util.writeDate(input.getRevision()) : withoutRevision;
-    }
-
-    @Override
-    public Optional<String> getModuleNamespace() {
-        return Optional.of(input.getNamespace().toString());
-    }
-
-    @Override
-    public Optional<String> getModuleName() {
-        return Optional.of(input.getName());
-    }
-
-    @Override
-    public Optional<String> getRevision() {
-        return Optional.of(hasRevision() ? QName.formattedRevision(input.getRevision()) : "");
-    }
-
-    private boolean hasRevision() {
-        return !input.getRevision().equals(NO_REVISION);
+        super(input, inputStream);
     }
 
     /**
@@ -66,10 +29,4 @@ public class FakeModuleBuilderCapability implements Capability{
     public Optional<String> getCapabilitySchema() {
         return Optional.absent();
     }
-
-    @Override
-    public List<String> getLocation() {
-        return NETCONF;
-    }
-
 }
index eb9d906272561e52fc219624a07ce285e65d791a..fdff6d510eee73e66eabced70fbf2a75b936ace4 100644 (file)
@@ -17,7 +17,7 @@ import org.opendaylight.controller.netconf.confignetconfconnector.util.Util;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.parser.builder.impl.ModuleBuilder;
 
-final class ModuleBuilderCapability implements Capability {
+class ModuleBuilderCapability implements Capability {
     private static final Date NO_REVISION = new Date(0);
     private static final List<String> NETCONF = Collections.singletonList("NETCONF");
     private final ModuleBuilder input;
@@ -30,7 +30,6 @@ final class ModuleBuilderCapability implements Capability {
 
     @Override
     public String getCapabilityUri() {
-        // FIXME capabilities in Netconf-impl need to check for NO REVISION
         final String withoutRevision = getModuleNamespace().get() + "?module=" + getModuleName().get();
         return hasRevision() ? withoutRevision + "&revision=" + Util.writeDate(input.getRevision()) : withoutRevision;
     }
index 93c1f9b92aded20f8f3bfc0766a9d25e4359b573..6f9ebede8d39f9e61825e4b14f8f2e2cce4870e3 100644 (file)
       <groupId>org.opendaylight.yangtools</groupId>
       <artifactId>mockito-configuration</artifactId>
     </dependency>
+  <dependency>
+      <groupId>org.opendaylight.yangtools</groupId>
+      <artifactId>yang-model-api</artifactId>
+  </dependency>
   </dependencies>
 
   <build>
diff --git a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/capability/BasicCapability.java b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/capability/BasicCapability.java
new file mode 100644 (file)
index 0000000..999f83c
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.netconf.util.capability;
+
+import com.google.common.base.Optional;
+import java.util.Collection;
+import java.util.Collections;
+import org.opendaylight.controller.netconf.api.Capability;
+
+/**
+ * Capability representing a basic, one-line, string based capability
+ */
+public class BasicCapability implements Capability {
+
+    private final String capability;
+
+    public BasicCapability(final String capability) {
+        this.capability = capability;
+    }
+
+    @Override
+    public String getCapabilityUri() {
+        return capability;
+    }
+
+    @Override
+    public Optional<String> getModuleNamespace() {
+        return Optional.absent();
+    }
+
+    @Override
+    public Optional<String> getModuleName() {
+        return Optional.absent();
+    }
+
+    @Override
+    public Optional<String> getRevision() {
+        return Optional.absent();
+    }
+
+    @Override
+    public Optional<String> getCapabilitySchema() {
+        return Optional.absent();
+    }
+
+    @Override
+    public Collection<String> getLocation() {
+        return Collections.emptyList();
+    }
+
+    @Override
+    public String toString() {
+        return capability;
+    }
+}
diff --git a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/capability/YangModuleCapability.java b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/capability/YangModuleCapability.java
new file mode 100644 (file)
index 0000000..e41affd
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.netconf.util.capability;
+
+import com.google.common.base.Optional;
+import org.opendaylight.yangtools.yang.common.SimpleDateFormatUtil;
+import org.opendaylight.yangtools.yang.model.api.Module;
+
+/**
+ * Yang model representing capability.
+ */
+public final class YangModuleCapability extends BasicCapability {
+
+    private final String content;
+    private final String revision;
+    private final String moduleName;
+    private final String moduleNamespace;
+
+    public YangModuleCapability(final Module module, final String moduleContent) {
+        super(toCapabilityURI(module));
+        this.content = moduleContent;
+        this.moduleName = module.getName();
+        this.moduleNamespace = module.getNamespace().toString();
+        this.revision = SimpleDateFormatUtil.getRevisionFormat().format(module.getRevision());
+    }
+
+    @Override
+    public Optional<String> getCapabilitySchema() {
+        return Optional.of(content);
+    }
+
+    private static String toCapabilityURI(final Module module) {
+        return String.valueOf(module.getNamespace()) + "?module="
+                + module.getName() + "&revision=" + SimpleDateFormatUtil.getRevisionFormat().format(module.getRevision());
+    }
+
+    @Override
+    public Optional<String> getModuleName() {
+        return Optional.of(moduleName);
+    }
+
+    @Override
+    public Optional<String> getModuleNamespace() {
+        return Optional.of(moduleNamespace);
+    }
+
+    @Override
+    public Optional<String> getRevision() {
+        return Optional.of(revision);
+    }
+}