Merge changes Ifd28301d,I38220acb,I9bad24df
authorTony Tkacik <ttkacik@cisco.com>
Tue, 29 Jul 2014 09:29:39 +0000 (09:29 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Tue, 29 Jul 2014 09:29:39 +0000 (09:29 +0000)
* changes:
  WIP: Backwards compatible MountPointService
  Fix children element lookup in XmlElement
  Fix config attributes with same names for different modules.

19 files changed:
opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/controller/config/yang/protocol/framework/ReconnectImmediatelyStrategyFactoryModule.java
opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/controller/config/yang/protocol/framework/TimedReconnectStrategyFactoryModule.java
opendaylight/commons/protocol-framework/src/main/yang/odl-protocol-framework-cfg.yang
opendaylight/commons/protocol-framework/src/test/java/org/opendaylight/controller/config/yang/protocol/framework/ReconnectImmediatelyStrategyModuleTest.java
opendaylight/commons/protocol-framework/src/test/java/org/opendaylight/controller/config/yang/protocol/framework/TimedReconnectStrategyModuleTest.java
opendaylight/distribution/opendaylight/src/main/resources/configuration/initial/01-md-sal.xml
opendaylight/md-sal/sal-dom-broker/pom.xml
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/dom/impl/DomBrokerImplModule.java
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/mount/DOMMountPointServiceImpl.java
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BackwardsCompatibleMountPoint.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BackwardsCompatibleMountPointManager.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/osgi/DOMMountPointServiceProxy.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/osgi/ProxyFactory.java
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/util/ProxySchemaContext.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-broker/src/test/java/org/opendaylight/controller/sal/dom/broker/BackwardsCompatibleMountPointManagerTest.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-broker/src/test/java/org/opendaylight/controller/sal/dom/broker/BackwardsCompatibleMountPointTest.java [new file with mode: 0644]
opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/config/yang/inmemory_datastore_provider/InMemoryOperationalDataStoreProviderModule.java
opendaylight/md-sal/sal-inmemory-datastore/src/main/yang/opendaylight-inmemory-datastore-provider.yang
opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/xml/XmlElement.java

index 580a53b..12b771d 100644 (file)
@@ -32,14 +32,14 @@ public final class ReconnectImmediatelyStrategyFactoryModule extends org.openday
 
     @Override
     protected void customValidation(){
-        JmxAttributeValidationException.checkNotNull(getTimeout(), "value is not set.", timeoutJmxAttribute);
-        JmxAttributeValidationException.checkCondition(getTimeout() >= 0, "value " + getTimeout() + " is less than 0",
-                timeoutJmxAttribute);
+        JmxAttributeValidationException.checkNotNull(getReconnectTimeout(), "value is not set.", reconnectTimeoutJmxAttribute);
+        JmxAttributeValidationException.checkCondition(getReconnectTimeout() >= 0, "value " + getReconnectTimeout() + " is less than 0",
+                reconnectTimeoutJmxAttribute);
     }
 
     @Override
     public java.lang.AutoCloseable createInstance() {
-        return new ReconnectImmediatelyStrategyFactoryCloseable(getExecutorDependency(), getTimeout());
+        return new ReconnectImmediatelyStrategyFactoryCloseable(getReconnectExecutorDependency(), getReconnectTimeout());
     }
 
     private static final class ReconnectImmediatelyStrategyFactoryCloseable implements ReconnectStrategyFactory, AutoCloseable {
index b8849c7..0b4a7ba 100644 (file)
@@ -49,7 +49,7 @@ public final class TimedReconnectStrategyFactoryModule extends org.opendaylight.
 
     @Override
     public java.lang.AutoCloseable createInstance() {
-        return new TimedReconnectStrategyFactoryCloseable(getExecutorDependency(),
+        return new TimedReconnectStrategyFactoryCloseable(getTimedReconnectExecutorDependency(),
                 getConnectTime(), getMinSleep(), getSleepFactor().doubleValue(), getMaxSleep(), getMaxAttempts(),
                 getDeadline());
     }
index 1856369..cd84d4a 100644 (file)
@@ -77,12 +77,12 @@ module protocol-framework {
         case reconnect-immediately-strategy-factory {
             when "/config:modules/config:module/config:type = 'reconnect-immediately-strategy-factory'";
 
-            leaf timeout {
+            leaf reconnect-timeout {
                 mandatory true;
                 type int32;
             }
 
-            container executor {
+            container reconnect-executor {
                 uses config:service-ref {
                     refine type {
                         mandatory true;
@@ -138,7 +138,7 @@ module protocol-framework {
                 units "milliseconds";
             }
 
-            container executor {
+            container timed-reconnect-executor {
                 uses config:service-ref {
                     refine type {
                         mandatory true;
index 9beadc4..cfdf3bf 100644 (file)
@@ -78,7 +78,7 @@ public class ReconnectImmediatelyStrategyModuleTest extends AbstractConfigTest {
         final ReconnectImmediatelyStrategyFactoryModuleMXBean mxBean = transaction.newMBeanProxy(
                 transaction.lookupConfigBean(FACTORY_NAME, INSTANCE_NAME),
                 ReconnectImmediatelyStrategyFactoryModuleMXBean.class);
-        mxBean.setTimeout(200);
+        mxBean.setReconnectTimeout(200);
         final CommitStatus status = transaction.commit();
         assertBeanCount(1, FACTORY_NAME);
         assertStatus(status, 0, 1, 1);
@@ -99,8 +99,8 @@ public class ReconnectImmediatelyStrategyModuleTest extends AbstractConfigTest {
         final ObjectName nameCreated = transaction.createModule(FACTORY_NAME, INSTANCE_NAME);
         final ReconnectImmediatelyStrategyFactoryModuleMXBean mxBean = transaction.newMBeanProxy(nameCreated,
                 ReconnectImmediatelyStrategyFactoryModuleMXBean.class);
-        mxBean.setTimeout(timeout);
-        mxBean.setExecutor(GlobalEventExecutorUtil.create(transaction));
+        mxBean.setReconnectTimeout(timeout);
+        mxBean.setReconnectExecutor(GlobalEventExecutorUtil.create(transaction));
         return nameCreated;
     }
 
index a8cdff7..1c068a9 100644 (file)
@@ -7,6 +7,13 @@
  */
 package org.opendaylight.controller.config.yang.protocol.framework;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.math.BigDecimal;
+import javax.management.InstanceAlreadyExistsException;
+import javax.management.ObjectName;
 import org.junit.Before;
 import org.junit.Test;
 import org.opendaylight.controller.config.api.ConflictingVersionException;
@@ -17,14 +24,6 @@ import org.opendaylight.controller.config.manager.impl.factoriesresolver.Hardcod
 import org.opendaylight.controller.config.util.ConfigTransactionJMXClient;
 import org.opendaylight.controller.config.yang.netty.eventexecutor.GlobalEventExecutorModuleFactory;
 
-import javax.management.InstanceAlreadyExistsException;
-import javax.management.ObjectName;
-import java.math.BigDecimal;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
 public class TimedReconnectStrategyModuleTest extends AbstractConfigTest {
 
     private static final String INSTANCE_NAME = "timed-reconect-stategy-facotry-impl";
@@ -158,7 +157,7 @@ public class TimedReconnectStrategyModuleTest extends AbstractConfigTest {
         mxBean.setMaxSleep(maxSleep);
         mxBean.setMinSleep(minSleep);
         mxBean.setSleepFactor(sleepFactor);
-        mxBean.setExecutor(GlobalEventExecutorUtil.create(transaction));
+        mxBean.setTimedReconnectExecutor(GlobalEventExecutorUtil.create(transaction));
         return nameCreated;
     }
 
index 9534094..03da7f0 100644 (file)
                 <module>
                     <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:inmemory-datastore-provider">prefix:inmemory-operational-datastore-provider</type>
                     <name>operational-store-service</name>
-                    <schema-service>
+                    <operational-schema-service>
                         <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:schema-service</type>
                         <name>yang-schema-service</name>
-                    </schema-service>
+                    </operational-schema-service>
                 </module>
                 <!--
                      Tree-based in-memory data store. This is the data store which is currently
index 022882f..96e353b 100644 (file)
       <groupId>org.slf4j</groupId>
       <artifactId>slf4j-api</artifactId>
     </dependency>
+
+    <dependency>
+      <groupId>org.opendaylight.yangtools</groupId>
+      <artifactId>mockito-configuration</artifactId>
+      <scope>test</scope>
+    </dependency>
     <dependency>
       <groupId>org.slf4j</groupId>
       <artifactId>slf4j-simple</artifactId>
           <instructions>
             <Bundle-Name>${project.groupId}.${project.artifactId}</Bundle-Name>
             <Bundle-Activator>org.opendaylight.controller.sal.dom.broker.osgi.SchemaServiceActivator</Bundle-Activator>
-            <Export-Package>org.opendaylight.controller.sal.dom.broker.spi</Export-Package>
-            <Private-Package>org.opendaylight.controller.sal.dom.broker,
+            <Export-Package>org.opendaylight.controller.sal.dom.broker.spi,
+                            <!--sal.broker.impl is exported for sal-netconf-connector to use SchemaAwareRpcRegistry.-->
+                            <!-- TODO Remove sal.broker.impl from export when SchemaAwareRpcRegistry is not used in connector anymore -->
                             org.opendaylight.controller.sal.dom.broker.impl,
                             org.opendaylight.controller.sal.dom.broker.impl.*,
+            </Export-Package>
+            <Private-Package>org.opendaylight.controller.sal.dom.broker,
                             org.opendaylight.controller.sal.dom.broker.osgi,
                             org.opendaylight.controller.sal.dom.broker.util,
                             org.opendaylight.controller.config.yang.md.sal.dom.impl,
-                            org.opendaylight.controller.config.yang.md.sal.dom.statistics,
+                            org.opendaylight.controller.config.yang.md.sal.dom.statistics,\
                             org.opendaylight.controller.md.sal.dom.broker.impl,
                             org.opendaylight.controller.md.sal.dom.broker.impl.*,
                             org.opendaylight.yangtools.yang.util,
index 998d884..34d231c 100644 (file)
@@ -7,8 +7,12 @@
  */
 package org.opendaylight.controller.config.yang.md.sal.dom.impl;
 
+import com.google.common.collect.ClassToInstanceMap;
+import com.google.common.collect.MutableClassToInstanceMap;
 import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
+import org.opendaylight.controller.md.sal.dom.api.DOMMountPointService;
 import org.opendaylight.controller.md.sal.dom.broker.impl.compat.BackwardsCompatibleDataBroker;
+import org.opendaylight.controller.md.sal.dom.broker.impl.mount.DOMMountPointServiceImpl;
 import org.opendaylight.controller.sal.core.api.BrokerService;
 import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry;
 import org.opendaylight.controller.sal.core.api.data.DataBrokerService;
@@ -17,18 +21,15 @@ import org.opendaylight.controller.sal.core.api.data.DataStore;
 import org.opendaylight.controller.sal.core.api.model.SchemaService;
 import org.opendaylight.controller.sal.core.api.mount.MountProvisionService;
 import org.opendaylight.controller.sal.core.api.mount.MountService;
+import org.opendaylight.controller.sal.dom.broker.BackwardsCompatibleMountPointManager;
 import org.opendaylight.controller.sal.dom.broker.BrokerImpl;
 import org.opendaylight.controller.sal.dom.broker.DataBrokerImpl;
 import org.opendaylight.controller.sal.dom.broker.GlobalBundleScanningSchemaServiceImpl;
-import org.opendaylight.controller.sal.dom.broker.MountPointManagerImpl;
 import org.opendaylight.controller.sal.dom.broker.impl.SchemaAwareDataStoreAdapter;
 import org.opendaylight.controller.sal.dom.broker.impl.SchemaAwareRpcBroker;
 import org.opendaylight.controller.sal.dom.broker.impl.SchemaContextProviders;
 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
 
-import com.google.common.collect.ClassToInstanceMap;
-import com.google.common.collect.MutableClassToInstanceMap;
-
 /**
 *
 */
@@ -72,10 +73,13 @@ public final class DomBrokerImplModule extends org.opendaylight.controller.confi
         services.putInstance(DataProviderService.class,legacyData);
         services.putInstance(DataBrokerService.class, legacyData);
 
+        final DOMMountPointService mountService = new DOMMountPointServiceImpl();
+        services.putInstance(DOMMountPointService.class, mountService);
 
-        MountPointManagerImpl mountService = new MountPointManagerImpl();
-        services.putInstance(MountService.class, mountService);
-        services.putInstance(MountProvisionService.class, mountService);
+        // TODO remove backwards service, use only new DOMMountPointService
+        final MountProvisionService backwardsMountService = new BackwardsCompatibleMountPointManager(mountService);
+        services.putInstance(MountService.class, backwardsMountService);
+        services.putInstance(MountProvisionService.class, backwardsMountService);
 
         return new BrokerImpl(router, services);
     }
index cdb78fc..9dd1808 100644 (file)
@@ -8,9 +8,12 @@
 
 package org.opendaylight.controller.md.sal.dom.broker.impl.mount;
 
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ClassToInstanceMap;
+import com.google.common.collect.MutableClassToInstanceMap;
 import java.util.HashMap;
 import java.util.Map;
-
 import org.opendaylight.controller.md.sal.dom.api.DOMMountPoint;
 import org.opendaylight.controller.md.sal.dom.api.DOMMountPointService;
 import org.opendaylight.controller.md.sal.dom.api.DOMService;
@@ -22,20 +25,15 @@ import org.opendaylight.yangtools.concepts.util.ListenerRegistry;
 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 
-import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
-import com.google.common.collect.ClassToInstanceMap;
-import com.google.common.collect.MutableClassToInstanceMap;
-
 public class DOMMountPointServiceImpl implements DOMMountPointService {
 
-    private final Map<InstanceIdentifier, SimpleDOMMountPoint> mountPoints = new HashMap<>();
+    private final Map<InstanceIdentifier, DOMMountPoint> mountPoints = new HashMap<>();
 
     private final ListenerRegistry<MountProvisionListener> listeners = ListenerRegistry.create();
 
     @Override
     public Optional<DOMMountPoint> getMountPoint(final InstanceIdentifier path) {
-        return Optional.<DOMMountPoint>fromNullable(mountPoints.get(path));
+        return Optional.fromNullable(mountPoints.get(path));
     }
 
     @Override
@@ -51,21 +49,35 @@ public class DOMMountPointServiceImpl implements DOMMountPointService {
         }
     }
 
+    public void notifyMountRemoved(final InstanceIdentifier identifier) {
+        for (final ListenerRegistration<MountProvisionListener> listener : listeners
+                .getListeners()) {
+            listener.getInstance().onMountPointRemoved(identifier);
+        }
+    }
+
     @Override
     public ListenerRegistration<MountProvisionListener> registerProvisionListener(
             final MountProvisionListener listener) {
         return listeners.register(listener);
     }
 
-    public ObjectRegistration<DOMMountPoint> registerMountPoint(final SimpleDOMMountPoint mountPoint) {
+    public ObjectRegistration<DOMMountPoint> registerMountPoint(final DOMMountPoint mountPoint) {
         synchronized (mountPoints) {
             Preconditions.checkState(!mountPoints.containsKey(mountPoint.getIdentifier()), "Mount point already exists");
             mountPoints.put(mountPoint.getIdentifier(), mountPoint);
         }
         notifyMountCreated(mountPoint.getIdentifier());
 
-        // FIXME this shouldnt be null
-        return null;
+        return new MountRegistration(mountPoint);
+    }
+
+    public void unregisterMountPoint(final InstanceIdentifier mountPointId) {
+        synchronized (mountPoints) {
+            Preconditions.checkState(mountPoints.containsKey(mountPointId), "Mount point does not exist");
+            mountPoints.remove(mountPointId);
+        }
+        notifyMountRemoved(mountPointId);
     }
 
     public class DOMMountPointBuilderImpl implements DOMMountPointBuilder {
@@ -98,4 +110,22 @@ public class DOMMountPointServiceImpl implements DOMMountPointService {
             return registerMountPoint(mountPoint);
         }
     }
+
+    private final class MountRegistration implements ObjectRegistration<DOMMountPoint> {
+        private final DOMMountPoint mountPoint;
+
+        public MountRegistration(final DOMMountPoint mountPoint) {
+            this.mountPoint = mountPoint;
+        }
+
+        @Override
+        public DOMMountPoint getInstance() {
+            return mountPoint;
+        }
+
+        @Override
+        public void close() throws Exception {
+            unregisterMountPoint(mountPoint.getIdentifier());
+        }
+    }
 }
diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BackwardsCompatibleMountPoint.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BackwardsCompatibleMountPoint.java
new file mode 100644 (file)
index 0000000..1a1ca00
--- /dev/null
@@ -0,0 +1,561 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html.
+ */
+package org.opendaylight.controller.sal.dom.broker;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.JdkFutureAdapters;
+import com.google.common.util.concurrent.ListenableFuture;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import javax.annotation.Nullable;
+import org.opendaylight.controller.md.sal.common.api.RegistrationListener;
+import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
+import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler;
+import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandlerRegistration;
+import org.opendaylight.controller.md.sal.common.api.data.DataReader;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
+import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener;
+import org.opendaylight.controller.md.sal.common.impl.ListenerRegistry;
+import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizationException;
+import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizer;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataChangeListener;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
+import org.opendaylight.controller.md.sal.dom.api.DOMMountPoint;
+import org.opendaylight.controller.md.sal.dom.api.DOMMountPointService;
+import org.opendaylight.controller.md.sal.dom.api.DOMService;
+import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain;
+import org.opendaylight.controller.md.sal.dom.broker.impl.compat.BackwardsCompatibleDataBroker;
+import org.opendaylight.controller.sal.common.DataStoreIdentifier;
+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.RoutedRpcDefaultImplementation;
+import org.opendaylight.controller.sal.core.api.RpcImplementation;
+import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry;
+import org.opendaylight.controller.sal.core.api.RpcRegistrationListener;
+import org.opendaylight.controller.sal.core.api.RpcRoutingContext;
+import org.opendaylight.controller.sal.core.api.data.DataChangeListener;
+import org.opendaylight.controller.sal.core.api.data.DataModificationTransaction;
+import org.opendaylight.controller.sal.core.api.data.DataProviderService;
+import org.opendaylight.controller.sal.core.api.data.DataValidator;
+import org.opendaylight.controller.sal.core.api.model.SchemaService;
+import org.opendaylight.controller.sal.core.api.mount.MountProvisionInstance;
+import org.opendaylight.controller.sal.core.api.notify.NotificationListener;
+import org.opendaylight.controller.sal.core.api.notify.NotificationPublishService;
+import org.opendaylight.controller.sal.dom.broker.impl.NotificationRouterImpl;
+import org.opendaylight.controller.sal.dom.broker.impl.SchemaAwareRpcBroker;
+import org.opendaylight.controller.sal.dom.broker.impl.SchemaContextProvider;
+import org.opendaylight.controller.sal.dom.broker.spi.NotificationRouter;
+import org.opendaylight.controller.sal.dom.broker.util.ProxySchemaContext;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.concepts.Registration;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaServiceListener;
+
+public class BackwardsCompatibleMountPoint implements MountProvisionInstance, SchemaContextProvider, SchemaService {
+
+    private final DataProviderService dataReader;
+    private final DataReader<InstanceIdentifier,CompositeNode> readWrapper;
+
+    private final InstanceIdentifier mountPath;
+    private final NotificationPublishService notificationPublishService;
+    private final RpcProvisionRegistry rpcs;
+
+    private final ListenerRegistry<SchemaServiceListener> schemaListenerRegistry = new ListenerRegistry<>();
+
+    private SchemaContext schemaContext;
+
+    public BackwardsCompatibleMountPoint(final InstanceIdentifier path, final DOMMountPointService.DOMMountPointBuilder mountPointBuilder) {
+        this.mountPath = Preconditions.checkNotNull(path);
+        Preconditions.checkNotNull(mountPointBuilder);
+
+        dataReader = new DataBrokerImpl();
+        readWrapper = new ReadWrapper();
+        notificationPublishService = new DelgatingNotificationPublishService();
+        rpcs = new SchemaAwareRpcBroker(path.toString(), this);
+
+        mountPointBuilder.addService(DOMDataBroker.class, new BackwardsCompatibleDomStore(dataReader, this));
+        mountPointBuilder.addService(NotificationPublishService.class, notificationPublishService);
+        mountPointBuilder.addService(RpcProvisionRegistry.class, rpcs);
+
+        mountPointBuilder.addInitialSchemaContext(new ProxySchemaContext(this));
+
+        mountPointBuilder.register();
+    }
+
+    public BackwardsCompatibleMountPoint(final InstanceIdentifier path, final DOMMountPoint mount) {
+        this.mountPath = Preconditions.checkNotNull(path);
+        Preconditions.checkNotNull(mount);
+
+        final DOMDataBroker domBroker = getServiceWithCheck(mount, DOMDataBroker.class);
+
+        this.schemaContext = mount.getSchemaContext();
+        dataReader = new BackwardsCompatibleDataBroker(domBroker, this);
+        readWrapper = new ReadWrapper();
+
+        notificationPublishService = getServiceWithCheck(mount, NotificationPublishService.class);
+        rpcs = getServiceWithCheck(mount, RpcProvisionRegistry.class);
+    }
+
+    private <T extends DOMService> T getServiceWithCheck(final DOMMountPoint mount, final Class<T> type) {
+        final Optional<T> serviceOptional = mount.getService(type);
+        Preconditions.checkArgument(serviceOptional.isPresent(), "Service {} has to be set in {}. " +
+                "Cannot construct backwards compatible mount wrapper without it", type, mount);
+        return serviceOptional.get();
+    }
+
+    @Override
+    public void addModule(final Module module) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void removeModule(final Module module) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public SchemaContext getSessionContext() {
+        return getSchemaContext();
+    }
+
+    @Override
+    public SchemaContext getGlobalContext() {
+        return getSchemaContext();
+    }
+
+    @Override
+    public ListenerRegistration<SchemaServiceListener> registerSchemaServiceListener(final SchemaServiceListener listener) {
+        return schemaListenerRegistry.register(listener);
+    }
+
+    @Override
+    public void publish(final CompositeNode notification) {
+        notificationPublishService.publish(notification);
+    }
+
+    @Override
+    public ListenerRegistration<NotificationListener> addNotificationListener(final QName notification, final NotificationListener listener) {
+        return notificationPublishService.addNotificationListener(notification, listener);
+    }
+
+    // TODO Read wrapper is never used ... same in org.opendaylight.controller.sal.dom.broker.MountPointImpl
+    public DataReader<InstanceIdentifier, CompositeNode> getReadWrapper() {
+        return readWrapper;
+    }
+
+    @Override
+    public CompositeNode readConfigurationData(final InstanceIdentifier path) {
+        return dataReader.readConfigurationData(path);
+    }
+
+    @Override
+    public CompositeNode readOperationalData(final InstanceIdentifier path) {
+        return dataReader.readOperationalData(path);
+    }
+
+    @Override
+    public Registration registerOperationalReader(
+            final InstanceIdentifier path, final DataReader<InstanceIdentifier, CompositeNode> reader) {
+        return dataReader.registerOperationalReader(path, reader);
+    }
+
+    @Override
+    public Registration registerConfigurationReader(
+            final InstanceIdentifier path, final DataReader<InstanceIdentifier, CompositeNode> reader) {
+        return dataReader.registerConfigurationReader(path, reader);
+    }
+
+    @Override
+    public RoutedRpcRegistration addRoutedRpcImplementation(final QName rpcType, final RpcImplementation implementation) {
+        return rpcs.addRoutedRpcImplementation(rpcType, implementation);
+    }
+
+    @Override
+    public void setRoutedRpcDefaultDelegate(final RoutedRpcDefaultImplementation defaultImplementation) {
+        rpcs.setRoutedRpcDefaultDelegate(defaultImplementation);
+    }
+
+    @Override
+    public RpcRegistration addRpcImplementation(final QName rpcType, final RpcImplementation implementation)
+            throws IllegalArgumentException {
+        return rpcs.addRpcImplementation(rpcType, implementation);
+    }
+
+    @Override
+    public Set<QName> getSupportedRpcs() {
+        return rpcs.getSupportedRpcs();
+    }
+
+    @Override
+    public ListenableFuture<RpcResult<CompositeNode>> invokeRpc(final QName rpc, final CompositeNode input) {
+        return rpcs.invokeRpc(rpc, input);
+    }
+
+    @Override
+    public ListenerRegistration<RpcRegistrationListener> addRpcRegistrationListener(final RpcRegistrationListener listener) {
+        return rpcs.addRpcRegistrationListener(listener);
+    }
+
+    @Override
+    public ListenableFuture<RpcResult<CompositeNode>> rpc(final QName type, final CompositeNode input) {
+        return rpcs.invokeRpc(type, input);
+    }
+
+    @Override
+    public DataModificationTransaction beginTransaction() {
+        return dataReader.beginTransaction();
+    }
+
+    @Override
+    public ListenerRegistration<DataChangeListener> registerDataChangeListener(final InstanceIdentifier path,
+            final DataChangeListener listener) {
+        return dataReader.registerDataChangeListener(path, listener);
+    }
+
+    @Override
+    public Registration registerCommitHandler(
+            final InstanceIdentifier path, final DataCommitHandler<InstanceIdentifier, CompositeNode> commitHandler) {
+        return dataReader.registerCommitHandler(path, commitHandler);
+    }
+
+    @Override
+    public void removeRefresher(final DataStoreIdentifier store, final DataRefresher refresher) {
+        // NOOP
+    }
+
+    @Override
+    public void addRefresher(final DataStoreIdentifier store, final DataRefresher refresher) {
+        // NOOP
+    }
+
+    @Override
+    public void addValidator(final DataStoreIdentifier store, final DataValidator validator) {
+        // NOOP
+    }
+    @Override
+    public void removeValidator(final DataStoreIdentifier store, final DataValidator validator) {
+        // NOOP
+    }
+
+    @Override
+    public SchemaContext getSchemaContext() {
+        return schemaContext;
+    }
+
+    @Override
+    public void setSchemaContext(final SchemaContext schemaContext) {
+        this.schemaContext = schemaContext;
+        for (ListenerRegistration<SchemaServiceListener> schemaServiceListenerListenerRegistration : schemaListenerRegistry.getListeners()) {
+            schemaServiceListenerListenerRegistration.getInstance().onGlobalContextUpdated(schemaContext);
+        }
+    }
+
+    class ReadWrapper implements DataReader<InstanceIdentifier, CompositeNode> {
+        private InstanceIdentifier shortenPath(final InstanceIdentifier path) {
+            InstanceIdentifier ret = null;
+            if(mountPath.contains(path)) {
+                final List<PathArgument> newArgs = path.getPath().subList(mountPath.getPath().size(), path.getPath().size());
+                ret = InstanceIdentifier.create(newArgs);
+            }
+            return ret;
+        }
+
+        @Override
+        public CompositeNode readConfigurationData(final InstanceIdentifier path) {
+            final InstanceIdentifier newPath = shortenPath(path);
+            if(newPath == null) {
+                return null;
+            }
+            return BackwardsCompatibleMountPoint.this.readConfigurationData(newPath);
+        }
+
+        @Override
+        public CompositeNode readOperationalData(final InstanceIdentifier path) {
+            final InstanceIdentifier newPath = shortenPath(path);
+            if(newPath == null) {
+                return null;
+            }
+            return BackwardsCompatibleMountPoint.this.readOperationalData(newPath);
+        }
+    }
+
+    @Override
+    public ListenerRegistration<RegistrationListener<DataCommitHandlerRegistration<InstanceIdentifier, CompositeNode>>> registerCommitHandlerListener(
+            final RegistrationListener<DataCommitHandlerRegistration<InstanceIdentifier, CompositeNode>> commitHandlerListener) {
+        return dataReader.registerCommitHandlerListener(commitHandlerListener);
+    }
+
+    @Override
+    public <L extends RouteChangeListener<RpcRoutingContext, InstanceIdentifier>> ListenerRegistration<L> registerRouteChangeListener(
+            final L listener) {
+        return rpcs.registerRouteChangeListener(listener);
+    }
+
+    @VisibleForTesting
+    static final class BackwardsCompatibleDomStore implements DOMDataBroker {
+        private final DataProviderService dataReader;
+        private final SchemaContextProvider schemaContextProvider;
+
+        public BackwardsCompatibleDomStore(final DataProviderService dataReader, final SchemaContextProvider schemaContextProvider) {
+            this.dataReader = dataReader;
+            this.schemaContextProvider = schemaContextProvider;
+        }
+
+        @Override
+        public DOMDataReadOnlyTransaction newReadOnlyTransaction() {
+            final DataNormalizer dataNormalizer = new DataNormalizer(schemaContextProvider.getSchemaContext());
+            return new BackwardsCompatibleReadTransaction(dataReader, dataNormalizer);
+        }
+
+        @Override
+        public DOMDataWriteTransaction newWriteOnlyTransaction() {
+            final DataNormalizer dataNormalizer = new DataNormalizer(schemaContextProvider.getSchemaContext());
+            return new BackwardsCompatibleWriteTransaction(dataReader, dataNormalizer);
+        }
+
+        @Override
+        public ListenerRegistration<DOMDataChangeListener> registerDataChangeListener(final LogicalDatastoreType store, final InstanceIdentifier path, final DOMDataChangeListener listener, final DataChangeScope triggeringScope) {
+            throw new UnsupportedOperationException("Register data listener not supported for mount point");
+        }
+
+        @Override
+        public DOMTransactionChain createTransactionChain(final TransactionChainListener listener) {
+            throw new UnsupportedOperationException("Transaction chain not supported for mount point");
+        }
+
+        @Override
+        public DOMDataReadWriteTransaction newReadWriteTransaction() {
+            final DataNormalizer dataNormalizer = new DataNormalizer(schemaContextProvider.getSchemaContext());
+            return new BackwardsCompatibleReadWriteTransaction(dataReader, dataNormalizer);
+        }
+
+        @VisibleForTesting
+        static final class BackwardsCompatibleReadTransaction implements DOMDataReadOnlyTransaction {
+            private final DataProviderService dataReader;
+            private final DataNormalizer normalizer;
+
+            public BackwardsCompatibleReadTransaction(final DataProviderService dataReader, final DataNormalizer normalizer) {
+                this.dataReader = dataReader;
+                this.normalizer = normalizer;
+            }
+
+            @Override
+            public Object getIdentifier() {
+                return this;
+            }
+
+            @Override
+            public void close() {
+                // NOOP
+            }
+
+            @Override
+            public ListenableFuture<Optional<NormalizedNode<?, ?>>> read(final LogicalDatastoreType store, final InstanceIdentifier path) {
+
+                CompositeNode rawData = null;
+
+                switch (store) {
+                    case CONFIGURATION: {
+                        rawData = dataReader.readConfigurationData(path);
+                        break;
+                    }
+                    case OPERATIONAL: {
+                        rawData = dataReader.readOperationalData(path);
+                        break;
+                    }
+                }
+                Preconditions.checkNotNull(rawData, "Unable to read %s data on path %s", store, path);
+
+                final Map.Entry<InstanceIdentifier, NormalizedNode<?, ?>> normalized = normalizer.toNormalized(path, rawData);
+                final Optional<NormalizedNode<?, ?>> normalizedNodeOptional = Optional.<NormalizedNode<?, ?>>fromNullable(normalized.getValue());
+                return com.google.common.util.concurrent.Futures.immediateFuture(normalizedNodeOptional);
+            }
+        }
+
+        @VisibleForTesting
+        static final class BackwardsCompatibleWriteTransaction implements DOMDataWriteTransaction {
+            private DataModificationTransaction oldTx;
+            private final DataNormalizer dataNormalizer;
+
+            public BackwardsCompatibleWriteTransaction(final DataProviderService dataReader, final DataNormalizer dataNormalizer) {
+                this.oldTx = dataReader.beginTransaction();
+                this.dataNormalizer = dataNormalizer;
+            }
+
+            @Override
+            public Object getIdentifier() {
+                return this;
+            }
+
+            @Override
+            public boolean cancel() {
+                oldTx = null;
+                return true;
+            }
+
+            @Override
+            public void put(final LogicalDatastoreType store, final InstanceIdentifier path, final NormalizedNode<?, ?> data) {
+                final CompositeNode legacyData = dataNormalizer.toLegacy(path, data);
+                try {
+                    final InstanceIdentifier legacyPath = dataNormalizer.toLegacy(path);
+
+                    switch (store) {
+                        case CONFIGURATION: {
+                            oldTx.putConfigurationData(legacyPath, legacyData);
+                            return;
+                        }
+                    }
+
+                    throw new IllegalArgumentException("Cannot put data " + path + " to datastore " + store);
+                } catch (final DataNormalizationException e) {
+                    throw new IllegalArgumentException(String.format("Cannot transform path %s to legacy format", path), e);
+                }
+            }
+
+            @Override
+            public void merge(final LogicalDatastoreType store, final InstanceIdentifier path, final NormalizedNode<?, ?> data) {
+                // TODO not supported
+                throw new UnsupportedOperationException("Merge not supported for mount point");
+            }
+
+            @Override
+            public void delete(final LogicalDatastoreType store, final InstanceIdentifier path) {
+                try {
+                    final InstanceIdentifier legacyPath = dataNormalizer.toLegacy(path);
+
+                    switch (store) {
+                        case CONFIGURATION: {
+                            oldTx.removeConfigurationData(legacyPath);
+                            return;
+                        }
+                    }
+                    throw new IllegalArgumentException("Cannot delete data " + path + " from datastore " + store);
+                } catch (final DataNormalizationException e) {
+                    throw new IllegalArgumentException(String.format("Cannot transform path %s to legacy format", path), e);
+                }
+            }
+
+            @Override
+            public CheckedFuture<Void, TransactionCommitFailedException> submit() {
+                final ListenableFuture<Void> commitAsVoid = Futures.transform(commit(), new Function<RpcResult<TransactionStatus>, Void>() {
+                    @Override
+                    public Void apply(@Nullable final RpcResult<TransactionStatus> input) {
+                        return null;
+                    }
+                });
+
+                return Futures.makeChecked(commitAsVoid, new Function<Exception, TransactionCommitFailedException>() {
+                    @Override
+                    public TransactionCommitFailedException apply(@Nullable final Exception input) {
+                        return new TransactionCommitFailedException("Commit failed", input);
+                    }
+                });
+            }
+
+            @Override
+            public ListenableFuture<RpcResult<TransactionStatus>> commit() {
+                return JdkFutureAdapters.listenInPoolThread(oldTx.commit());
+            }
+        }
+
+
+        @VisibleForTesting
+        static class BackwardsCompatibleReadWriteTransaction implements DOMDataReadWriteTransaction {
+
+            private final DataProviderService dataReader;
+            private final DataNormalizer dataNormalizer;
+            private final BackwardsCompatibleWriteTransaction delegateWriteTx;
+
+            public BackwardsCompatibleReadWriteTransaction(final DataProviderService dataReader, final DataNormalizer dataNormalizer) {
+                this.dataReader = dataReader;
+                this.dataNormalizer = dataNormalizer;
+                this.delegateWriteTx = new BackwardsCompatibleWriteTransaction(dataReader, dataNormalizer);
+            }
+
+            @Override
+            public Object getIdentifier() {
+                return this;
+            }
+
+            @Override
+            public ListenableFuture<Optional<NormalizedNode<?, ?>>> read(final LogicalDatastoreType store, final InstanceIdentifier path) {
+                return new BackwardsCompatibleReadTransaction(dataReader, dataNormalizer).read(store, path);
+            }
+
+            @Override
+            public boolean cancel() {
+                return delegateWriteTx.cancel();
+            }
+
+            @Override
+            public void put(final LogicalDatastoreType store, final InstanceIdentifier path, final NormalizedNode<?, ?> data) {
+                delegateWriteTx.put(store, path, data);
+            }
+
+            @Override
+            public void merge(final LogicalDatastoreType store, final InstanceIdentifier path, final NormalizedNode<?, ?> data) {
+                delegateWriteTx.merge(store, path, data);
+            }
+
+            @Override
+            public void delete(final LogicalDatastoreType store, final InstanceIdentifier path) {
+                delegateWriteTx.delete(store, path);
+            }
+
+            @Override
+            public CheckedFuture<Void, TransactionCommitFailedException> submit() {
+                return delegateWriteTx.submit();
+            }
+
+            @Override
+            public ListenableFuture<RpcResult<TransactionStatus>> commit() {
+                return delegateWriteTx.commit();
+            }
+        }
+    }
+
+    private class DelgatingNotificationPublishService implements NotificationPublishService {
+        private final NotificationRouter notificationRouter;
+
+        public DelgatingNotificationPublishService(final NotificationRouter notificationRouter) {
+            this.notificationRouter = notificationRouter;
+        }
+
+        private DelgatingNotificationPublishService() {
+            this(new NotificationRouterImpl());
+        }
+
+        @Override
+        public void publish(final CompositeNode notification) {
+            notificationRouter.publish(notification);
+        }
+
+        @Override
+        public ListenerRegistration<NotificationListener> addNotificationListener(final QName notification, final NotificationListener listener) {
+            return notificationRouter.addNotificationListener(notification, listener);
+        }
+    }
+}
diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BackwardsCompatibleMountPointManager.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BackwardsCompatibleMountPointManager.java
new file mode 100644 (file)
index 0000000..5c2a8e0
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html.
+ */
+package org.opendaylight.controller.sal.dom.broker;
+
+import static com.google.common.base.Preconditions.checkState;
+
+import com.google.common.base.Optional;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import org.opendaylight.controller.md.sal.dom.api.DOMMountPoint;
+import org.opendaylight.controller.md.sal.dom.api.DOMMountPointService;
+import org.opendaylight.controller.sal.core.api.mount.MountProvisionInstance;
+import org.opendaylight.controller.sal.core.api.mount.MountProvisionListener;
+import org.opendaylight.controller.sal.core.api.mount.MountProvisionService;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.concepts.util.ListenerRegistry;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+
+public class BackwardsCompatibleMountPointManager implements MountProvisionService, MountProvisionListener {
+
+    private final ListenerRegistry<MountProvisionListener> listeners = ListenerRegistry.create();
+    private final ConcurrentMap<InstanceIdentifier, MountProvisionInstance> mounts = new ConcurrentHashMap<>();
+
+    private final DOMMountPointService domMountPointService;
+
+    public BackwardsCompatibleMountPointManager(final DOMMountPointService domMountPointService) {
+        this.domMountPointService = domMountPointService;
+    }
+
+    @Override
+    public MountProvisionInstance createMountPoint(final InstanceIdentifier path) {
+        checkState(!mounts.containsKey(path), "Mount already created");
+        // Create mount point instance, wrap instance of new API with BackwardsCompatibleMountPoint to preserve backwards comatibility
+        final BackwardsCompatibleMountPoint mount = new BackwardsCompatibleMountPoint(path, domMountPointService.createMountPoint(path));
+        mounts.put(path, mount);
+        return mount;
+    }
+
+    public void notifyMountCreated(final InstanceIdentifier identifier) {
+        for (final ListenerRegistration<MountProvisionListener> listener : listeners.getListeners()) {
+            listener.getInstance().onMountPointCreated(identifier);
+        }
+    }
+
+    public void notifyMountRemoved(final InstanceIdentifier identifier) {
+        for (final ListenerRegistration<MountProvisionListener> listener : listeners.getListeners()) {
+            listener.getInstance().onMountPointRemoved(identifier);
+        }
+    }
+
+    @Override
+    public MountProvisionInstance createOrGetMountPoint(
+            final InstanceIdentifier path) {
+        final MountProvisionInstance mount = getMountPoint(path);
+        if (mount == null) {
+            return createMountPoint(path);
+        }
+        return mount;
+    }
+
+    @Override
+    public MountProvisionInstance getMountPoint(final InstanceIdentifier path) {
+        // If the mount point was created here, return directly
+        if(mounts.containsKey(path)) {
+            return mounts.get(path);
+        }
+
+        // If mount was created in underlying DOMMountService, wrap as MountProvisionInstance
+        final Optional<DOMMountPoint> mount = domMountPointService.getMountPoint(path);
+        if(mount.isPresent()) {
+            return new BackwardsCompatibleMountPoint(path, mount.get());
+        } else {
+            return null;
+        }
+    }
+
+    @Override
+    public ListenerRegistration<MountProvisionListener> registerProvisionListener(
+            final MountProvisionListener listener) {
+        return domMountPointService.registerProvisionListener(listener);
+    }
+
+    @Override
+    public void onMountPointCreated(final InstanceIdentifier path) {
+        notifyMountCreated(path);
+    }
+
+    @Override
+    public void onMountPointRemoved(final InstanceIdentifier path) {
+            notifyMountRemoved(path);
+    }
+}
diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/osgi/DOMMountPointServiceProxy.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/osgi/DOMMountPointServiceProxy.java
new file mode 100644 (file)
index 0000000..4c73e0b
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html.
+ */
+package org.opendaylight.controller.sal.dom.broker.osgi;
+
+import com.google.common.base.Optional;
+import org.opendaylight.controller.md.sal.dom.api.DOMMountPoint;
+import org.opendaylight.controller.md.sal.dom.api.DOMMountPointService;
+import org.opendaylight.controller.sal.core.api.mount.MountProvisionListener;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.osgi.framework.ServiceReference;
+
+public class DOMMountPointServiceProxy extends AbstractBrokerServiceProxy<DOMMountPointService> implements DOMMountPointService{
+
+
+    public DOMMountPointServiceProxy(final ServiceReference<DOMMountPointService> ref, final DOMMountPointService delegate) {
+        super(ref, delegate);
+    }
+
+    @Override
+    public Optional<DOMMountPoint> getMountPoint(final InstanceIdentifier path) {
+        return getDelegate().getMountPoint(path);
+    }
+
+    @Override
+    public DOMMountPointBuilder createMountPoint(final InstanceIdentifier path) {
+        return getDelegate().createMountPoint(path);
+    }
+
+    public ListenerRegistration<MountProvisionListener> registerProvisionListener(final MountProvisionListener listener) {
+        return getDelegate().registerProvisionListener(listener);
+    }
+}
index c2d6add..2ce2bac 100644 (file)
@@ -9,6 +9,7 @@ package org.opendaylight.controller.sal.dom.broker.osgi;
 
 import java.util.Arrays;
 
+import org.opendaylight.controller.md.sal.dom.api.DOMMountPointService;
 import org.opendaylight.controller.sal.core.api.BrokerService;
 import org.osgi.framework.ServiceReference;
 import org.opendaylight.controller.sal.core.api.data.DataBrokerService;
@@ -66,6 +67,13 @@ public class ProxyFactory {
                 ((ServiceReference<MountProvisionService>) ref), service);
     }
 
+    private static Object _createProxyImpl(final ServiceReference<?> ref,
+            final DOMMountPointService service) {
+
+        return new DOMMountPointServiceProxy(
+                ((ServiceReference<DOMMountPointService>) ref), service);
+    }
+
     private static Object _createProxyImpl(final ServiceReference<?> ref,
             final SchemaService service) {
 
@@ -113,6 +121,8 @@ public class ProxyFactory {
             return _createProxyImpl(ref, (SchemaService) service);
         } else if (service instanceof NotificationService) {
             return _createProxyImpl(ref, (NotificationService) service);
+        } else if (service instanceof DOMMountPointService) {
+            return _createProxyImpl(ref, (DOMMountPointService) service);
         } else if (service != null) {
             return _createProxyImpl(ref, service);
         } else {
diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/util/ProxySchemaContext.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/util/ProxySchemaContext.java
new file mode 100644 (file)
index 0000000..311055f
--- /dev/null
@@ -0,0 +1,193 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html.
+ */
+
+package org.opendaylight.controller.sal.dom.broker.util;
+
+import java.net.URI;
+import java.util.Collection;
+import java.util.Date;
+import java.util.List;
+import java.util.Set;
+
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
+import org.opendaylight.yangtools.yang.model.api.ConstraintDefinition;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ExtensionDefinition;
+import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.ModuleIdentifier;
+import org.opendaylight.yangtools.yang.model.api.NotificationDefinition;
+import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaContextProvider;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+import org.opendaylight.yangtools.yang.model.api.Status;
+import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.UsesNode;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+
+/**
+ * ProxySchema Context for SchemaContextProviders
+ */
+public class ProxySchemaContext implements SchemaContext {
+
+    private final SchemaContextProvider schemaProvider;
+
+    public ProxySchemaContext(final SchemaContextProvider schemaProvider) {
+        this.schemaProvider = schemaProvider;
+    }
+
+    private SchemaContext getCurrentSchema() {
+        Preconditions.checkState(schemaProvider.getSchemaContext() != null, "Schema context unavailable from %s", schemaProvider);
+        return schemaProvider.getSchemaContext();
+    }
+
+    @Override
+    public Set<DataSchemaNode> getDataDefinitions() {
+        return getCurrentSchema().getDataDefinitions();
+    }
+
+    @Override
+    public Set<Module> getModules() {
+        return getCurrentSchema().getModules();
+    }
+
+    @Override
+    public Set<NotificationDefinition> getNotifications() {
+        return getCurrentSchema().getNotifications();
+    }
+
+    @Override
+    public Set<RpcDefinition> getOperations() {
+        return getCurrentSchema().getOperations();
+    }
+
+    @Override
+    public Set<ExtensionDefinition> getExtensions() {
+        return getCurrentSchema().getExtensions();
+    }
+
+    @Override
+    public Module findModuleByName(final String s, final Date date) {
+        return getCurrentSchema().findModuleByName(s, date);
+    }
+
+    @Override
+    public Set<Module> findModuleByNamespace(final URI uri) {
+        return getCurrentSchema().findModuleByNamespace(uri);
+    }
+
+    @Override
+    public Module findModuleByNamespaceAndRevision(final URI uri, final Date date) {
+        return getCurrentSchema().findModuleByNamespaceAndRevision(uri, date);
+    }
+
+    @Override
+    public Optional<String> getModuleSource(final ModuleIdentifier moduleIdentifier) {
+        return getCurrentSchema().getModuleSource(moduleIdentifier);
+    }
+
+    @Override
+    public Set<ModuleIdentifier> getAllModuleIdentifiers() {
+        return getCurrentSchema().getAllModuleIdentifiers();
+    }
+
+    @Override
+    public boolean isPresenceContainer() {
+        return getCurrentSchema().isPresenceContainer();
+    }
+
+    @Override
+    public Set<TypeDefinition<?>> getTypeDefinitions() {
+        return getCurrentSchema().getTypeDefinitions();
+    }
+
+    @Override
+    public Collection<DataSchemaNode> getChildNodes() {
+        return getCurrentSchema().getChildNodes();
+    }
+
+    @Override
+    public Set<GroupingDefinition> getGroupings() {
+        return getCurrentSchema().getGroupings();
+    }
+
+    @Override
+    public DataSchemaNode getDataChildByName(final QName qName) {
+        return getCurrentSchema().getDataChildByName(qName);
+    }
+
+    @Override
+    public DataSchemaNode getDataChildByName(final String s) {
+        return getCurrentSchema().getDataChildByName(s);
+    }
+
+    @Override
+    public Set<UsesNode> getUses() {
+        return getCurrentSchema().getUses();
+    }
+
+    @Override
+    public Set<AugmentationSchema> getAvailableAugmentations() {
+        return getCurrentSchema().getAvailableAugmentations();
+    }
+
+    @Override
+    public boolean isAugmenting() {
+        return getCurrentSchema().isAugmenting();
+    }
+
+    @Override
+    public boolean isAddedByUses() {
+        return getCurrentSchema().isAddedByUses();
+    }
+
+    @Override
+    public boolean isConfiguration() {
+        return getCurrentSchema().isConfiguration();
+    }
+
+    @Override
+    public ConstraintDefinition getConstraints() {
+        return getCurrentSchema().getConstraints();
+    }
+
+    @Override
+    public QName getQName() {
+        return getCurrentSchema().getQName();
+    }
+
+    @Override
+    public SchemaPath getPath() {
+        return getCurrentSchema().getPath();
+    }
+
+    @Override
+    public List<UnknownSchemaNode> getUnknownSchemaNodes() {
+        return getCurrentSchema().getUnknownSchemaNodes();
+    }
+
+    @Override
+    public String getDescription() {
+        return getCurrentSchema().getDescription();
+    }
+
+    @Override
+    public String getReference() {
+        return getCurrentSchema().getReference();
+    }
+
+    @Override
+    public Status getStatus() {
+        return getCurrentSchema().getStatus();
+    }
+}
diff --git a/opendaylight/md-sal/sal-dom-broker/src/test/java/org/opendaylight/controller/sal/dom/broker/BackwardsCompatibleMountPointManagerTest.java b/opendaylight/md-sal/sal-dom-broker/src/test/java/org/opendaylight/controller/sal/dom/broker/BackwardsCompatibleMountPointManagerTest.java
new file mode 100644 (file)
index 0000000..3b11ed0
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html.
+ */
+
+package org.opendaylight.controller.sal.dom.broker;
+
+import static junit.framework.Assert.fail;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+import org.opendaylight.controller.md.sal.dom.api.DOMMountPoint;
+import org.opendaylight.controller.md.sal.dom.api.DOMMountPointService;
+import org.opendaylight.controller.md.sal.dom.api.DOMService;
+import org.opendaylight.controller.md.sal.dom.broker.impl.mount.DOMMountPointServiceImpl;
+import org.opendaylight.controller.sal.core.api.mount.MountProvisionInstance;
+import org.opendaylight.controller.sal.core.api.mount.MountProvisionListener;
+import org.opendaylight.yangtools.concepts.ObjectRegistration;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Optional;
+
+public class BackwardsCompatibleMountPointManagerTest {
+    private static final Logger log = LoggerFactory.getLogger(BackwardsCompatibleMountPointManagerTest.class);
+
+    @Mock
+    private DOMMountPointServiceImpl domMountPointService;
+    @Mock
+    private DOMMountPointService.DOMMountPointBuilder mountBuilder;
+
+    private BackwardsCompatibleMountPointManager compatibleMountPointManager;
+    static final QName qName = QName.create("namespace", "12-12-1212", "mount");
+    static final InstanceIdentifier id = InstanceIdentifier.builder(qName).build();
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+        stubMountService();
+        compatibleMountPointManager = new BackwardsCompatibleMountPointManager(domMountPointService);
+    }
+
+    @Test
+    public void testCreateMountpointAlreadyCreated() throws Exception {
+        compatibleMountPointManager.createMountPoint(id);
+        verify(domMountPointService).createMountPoint(id);
+        verify(mountBuilder, times(3)).addService(any(Class.class), any(DOMService.class));
+        verify(mountBuilder).addInitialSchemaContext(any(SchemaContext.class));
+
+        try {
+            compatibleMountPointManager.createMountPoint(id);
+        } catch (final IllegalStateException e) {
+            log.debug("", e);
+            return;
+        }
+        fail("Should fail to create duplicate mount");
+    }
+
+    @Test
+    public void testCreateMountpointGetOrCreate() throws Exception {
+        compatibleMountPointManager = new BackwardsCompatibleMountPointManager(new DOMMountPointServiceImpl());
+
+        final MountProvisionListener listener = new MountProvisionListener() {
+            public int createdMounts = 0;
+
+            @Override
+            public void onMountPointCreated(final InstanceIdentifier path) {
+                if(createdMounts++ > 1 ) {
+                    fail("Only one mount point should have been created");
+                }
+            }
+
+            @Override
+            public void onMountPointRemoved(final InstanceIdentifier path) {}
+        };
+
+        compatibleMountPointManager.registerProvisionListener(listener);
+
+        final MountProvisionInstance m1 = compatibleMountPointManager.createOrGetMountPoint(id);
+        m1.setSchemaContext(mockSchemaContext());
+        compatibleMountPointManager.createOrGetMountPoint(id);
+        compatibleMountPointManager.createOrGetMountPoint(id);
+    }
+
+    private void stubMountService() {
+        doReturn(mockMountPointBuilder()).when(domMountPointService).createMountPoint(any(InstanceIdentifier.class));
+        doReturn(Optional.of(mockMountPoint())).when(domMountPointService).getMountPoint(any(InstanceIdentifier.class));
+    }
+
+    private DOMMountPoint mockMountPoint() {
+        final DOMMountPoint mock = mock(DOMMountPoint.class);
+        doAnswer(new Answer() {
+            @Override
+            public Object answer(final InvocationOnMock invocation) throws Throwable {
+                return Optional.of(mock(((Class<?>) invocation.getArguments()[0])));
+            }
+        }).when(mock).getService(any(Class.class));
+        doReturn(mockSchemaContext()).when(mock).getSchemaContext();
+        return mock;
+    }
+
+    static SchemaContext mockSchemaContext() {
+        final SchemaContext mock = mock(SchemaContext.class);
+        doReturn(qName).when(mock).getQName();
+        doReturn("schema").when(mock).toString();
+        doReturn(mock(DataSchemaNode.class)).when(mock).getDataChildByName(any(QName.class));
+        return mock;
+    }
+
+    private DOMMountPointService.DOMMountPointBuilder mockMountPointBuilder() {
+        doReturn(mountBuilder).when(mountBuilder).addService(any(Class.class), any(DOMService.class));
+        doReturn(mockObjectRegistration()).when(mountBuilder).register();
+        doReturn(mountBuilder).when(mountBuilder).addInitialSchemaContext(any(SchemaContext.class));
+        return mountBuilder;
+    }
+
+    private ObjectRegistration<?> mockObjectRegistration() {
+        return mock(ObjectRegistration.class);
+    }
+
+}
diff --git a/opendaylight/md-sal/sal-dom-broker/src/test/java/org/opendaylight/controller/sal/dom/broker/BackwardsCompatibleMountPointTest.java b/opendaylight/md-sal/sal-dom-broker/src/test/java/org/opendaylight/controller/sal/dom/broker/BackwardsCompatibleMountPointTest.java
new file mode 100644 (file)
index 0000000..5a36f71
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html.
+ */
+
+package org.opendaylight.controller.sal.dom.broker;
+
+import static junit.framework.Assert.fail;
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import com.google.common.base.Optional;
+import com.google.common.util.concurrent.ListenableFuture;
+import java.util.AbstractMap;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizationException;
+import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizer;
+import org.opendaylight.controller.sal.core.api.data.DataModificationTransaction;
+import org.opendaylight.controller.sal.core.api.data.DataProviderService;
+import org.opendaylight.controller.sal.dom.broker.impl.SchemaContextProvider;
+import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class BackwardsCompatibleMountPointTest {
+    private static final Logger log = LoggerFactory.getLogger(BackwardsCompatibleMountPointManagerTest.class);
+
+    private static final InstanceIdentifier id = BackwardsCompatibleMountPointManagerTest.id;
+    private final NormalizedNode<?, ?> normalizedNode = mockNormalizedNode();
+    private final CompositeNode compositeNode = mockCompositeNode();
+
+    @Mock
+    private DataProviderService oldBroker;
+    @Mock
+    private SchemaContextProvider schemaContextProvider;
+    @Mock
+    private DataModificationTransaction mockTx;
+
+    private BackwardsCompatibleMountPoint.BackwardsCompatibleDomStore backwardsCompatibleDomStore;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+        stubSchemaProvider();
+        stubOldBroker();
+        backwardsCompatibleDomStore = new BackwardsCompatibleMountPoint.BackwardsCompatibleDomStore(oldBroker, schemaContextProvider);
+    }
+
+    private void stubOldBroker() {
+        doReturn(compositeNode).when(oldBroker).readConfigurationData(id);
+        doReturn(compositeNode).when(oldBroker).readOperationalData(id);
+        doReturn(mockTx).when(oldBroker).beginTransaction();
+        doNothing().when(mockTx).putConfigurationData(id, compositeNode);
+        doNothing().when(mockTx).putOperationalData(id, compositeNode);
+        doReturn(com.google.common.util.concurrent.Futures.immediateFuture(RpcResultBuilder.success(TransactionStatus.COMMITED))).when(mockTx).commit();
+    }
+
+    private CompositeNode mockCompositeNode() {
+        final CompositeNode mock = mock(CompositeNode.class);
+        doReturn("node").when(mock).toString();
+        return mock;
+    }
+
+    private void stubSchemaProvider() {
+        doReturn(BackwardsCompatibleMountPointManagerTest.mockSchemaContext()).when(schemaContextProvider).getSchemaContext();
+    }
+
+    @Test
+    public void testBackwardsCompatibleBroker() throws Exception {
+        backwardsCompatibleDomStore.newReadOnlyTransaction();
+        backwardsCompatibleDomStore.newWriteOnlyTransaction();
+        backwardsCompatibleDomStore.newReadWriteTransaction();
+    }
+
+    @Test
+    public void testReadTransaction() throws Exception {
+        final BackwardsCompatibleMountPoint.BackwardsCompatibleDomStore.BackwardsCompatibleReadTransaction tx =
+                new BackwardsCompatibleMountPoint.BackwardsCompatibleDomStore.BackwardsCompatibleReadTransaction(oldBroker, mockNormalizer());
+
+        ListenableFuture<Optional<NormalizedNode<?, ?>>> read = tx.read(LogicalDatastoreType.CONFIGURATION, id);
+        assertEquals(normalizedNode, read.get().get());
+        verify(oldBroker).readConfigurationData(id);
+
+        read = tx.read(LogicalDatastoreType.OPERATIONAL, id);
+        assertEquals(normalizedNode, read.get().get());
+
+        verify(oldBroker).readOperationalData(id);
+    }
+
+    @Test
+    public void testReadWriteTransactionOperational() throws Exception {
+        final BackwardsCompatibleMountPoint.BackwardsCompatibleDomStore.BackwardsCompatibleWriteTransaction tx =
+                new BackwardsCompatibleMountPoint.BackwardsCompatibleDomStore.BackwardsCompatibleWriteTransaction(oldBroker, mockNormalizer());
+
+        verify(oldBroker).beginTransaction();
+
+        tx.put(LogicalDatastoreType.CONFIGURATION, id, normalizedNode);
+        verify(mockTx).putConfigurationData(id, compositeNode);
+
+        tx.put(LogicalDatastoreType.CONFIGURATION, id, normalizedNode);
+        verify(mockTx, times(2)).putConfigurationData(id, compositeNode);
+
+        tx.commit();
+        verify(mockTx).commit();
+    }
+
+
+    @Test
+    public void testCannotPutOperational() throws Exception {
+        final BackwardsCompatibleMountPoint.BackwardsCompatibleDomStore.BackwardsCompatibleWriteTransaction tx =
+                new BackwardsCompatibleMountPoint.BackwardsCompatibleDomStore.BackwardsCompatibleWriteTransaction(oldBroker, mockNormalizer());
+
+        try {
+            tx.put(LogicalDatastoreType.OPERATIONAL, id, normalizedNode);
+        } catch (IllegalArgumentException e) {
+            // Cannot put operational data
+            log.debug("", e);
+            return;
+        }
+
+        fail("Should fail when putting operational data");
+    }
+
+    private DataNormalizer mockNormalizer() throws DataNormalizationException {
+        final DataNormalizer mock = mock(DataNormalizer.class);
+        doReturn(new AbstractMap.SimpleEntry<InstanceIdentifier, NormalizedNode<?, ?>>(id, normalizedNode) {})
+                .when(mock).toNormalized(any(InstanceIdentifier.class), any(CompositeNode.class));
+        doReturn(compositeNode).when(mock).toLegacy(any(InstanceIdentifier.class), any(NormalizedNode.class));
+        doReturn(id).when(mock).toLegacy(any(InstanceIdentifier.class));
+        return mock;
+    }
+
+    private NormalizedNode<?, ?> mockNormalizedNode() {
+        final NormalizedNode mock = mock(NormalizedNode.class);
+        doReturn("mockNormalizedNode").when(mock).toString();
+        return mock;
+    }
+}
\ No newline at end of file
index 172b0db..b39c9bb 100644 (file)
@@ -23,7 +23,7 @@ public class InMemoryOperationalDataStoreProviderModule extends org.opendaylight
     @Override
     public java.lang.AutoCloseable createInstance() {
       InMemoryDOMDataStore ids = new InMemoryDOMDataStore("DOM-OPER", MoreExecutors.listeningDecorator(Executors.newSingleThreadExecutor()));
-      getSchemaServiceDependency().registerSchemaServiceListener(ids);
+      getOperationalSchemaServiceDependency().registerSchemaServiceListener(ids);
       return ids;
     }
 
index 03220a3..d4f57b5 100644 (file)
@@ -58,7 +58,10 @@ module opendaylight-inmemory-datastore-provider {
             case inmemory-operational-datastore-provider {
                 when "/config:modules/config:module/config:type = 'inmemory-operational-datastore-provider'";
 
-                container schema-service {
+                // Yang does not allow two cases from same namespaces with same children
+                // Schema-service dependency renamed to operational-schema-service
+                // to prevent conflict with schema-service container from inmemory-config-datastore-provider
+                container operational-schema-service {
                   uses config:service-ref {
                        refine type {
                               mandatory false;
index 8780925..4e3a66b 100644 (file)
@@ -224,11 +224,17 @@ public final class XmlElement {
         });
     }
 
+    /**
+     *
+     * @param tagName tag name without prefix
+     * @return
+     */
     public List<XmlElement> getChildElements(final String tagName) {
         return getChildElementsInternal(new ElementFilteringStrategy() {
             @Override
             public boolean accept(Element e) {
-                return e.getTagName().equals(tagName);
+                // localName returns pure localName without prefix
+                return e.getLocalName().equals(tagName);
             }
         });
     }