WIP: Backwards compatible MountPointService 50/9150/19
authorMaros Marsalek <mmarsale@cisco.com>
Fri, 18 Jul 2014 12:29:39 +0000 (14:29 +0200)
committerMaros Marsalek <mmarsale@cisco.com>
Tue, 29 Jul 2014 06:45:44 +0000 (08:45 +0200)
Change-Id: Ifd28301ddd08d4edba93dba04a4d38c2ee13078a
Signed-off-by: Maros Marsalek <mmarsale@cisco.com>
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]

index 022882fcebd042404689f64abf2ed614894c3262..96e353b80e23c284885a48cf2302e9759cb29386 100644 (file)
       <groupId>org.slf4j</groupId>
       <artifactId>slf4j-api</artifactId>
     </dependency>
       <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>
     <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>
           <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.*,
                             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.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,
                             org.opendaylight.controller.md.sal.dom.broker.impl,
                             org.opendaylight.controller.md.sal.dom.broker.impl.*,
                             org.opendaylight.yangtools.yang.util,
index 998d884b0cde71cd2fe774352229a61afd98761d..34d231cf2ab332870ddfd9ca5b6cad6dd37e2d91 100644 (file)
@@ -7,8 +7,12 @@
  */
 package org.opendaylight.controller.config.yang.md.sal.dom.impl;
 
  */
 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.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.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;
 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.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.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 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);
 
         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);
     }
 
         return new BrokerImpl(router, services);
     }
index cdb78fc5921bc7e23132de35455d8960da93a8b9..9dd180866a573642171a4cb5d5306ca100afaa80 100644 (file)
@@ -8,9 +8,12 @@
 
 package org.opendaylight.controller.md.sal.dom.broker.impl.mount;
 
 
 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 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;
 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 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 {
 
 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) {
 
     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
     }
 
     @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);
     }
 
     @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());
 
         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 {
     }
 
     public class DOMMountPointBuilderImpl implements DOMMountPointBuilder {
@@ -98,4 +110,22 @@ public class DOMMountPointServiceImpl implements DOMMountPointService {
             return registerMountPoint(mountPoint);
         }
     }
             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 c2d6add17a07c8ffefa711618034b690d35040ae..2ce2bac86227f2e9b0decf770a68dea7f5bcd1bb 100644 (file)
@@ -9,6 +9,7 @@ package org.opendaylight.controller.sal.dom.broker.osgi;
 
 import java.util.Arrays;
 
 
 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;
 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);
     }
 
                 ((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) {
 
     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);
             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 {
         } 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