Proxy controller services in DOMMountPointServiceImpl 62/77562/18
authorJakub Morvay <jmorvay@frinx.io>
Tue, 6 Nov 2018 18:17:44 +0000 (19:17 +0100)
committerTom Pantelis <tompantelis@gmail.com>
Fri, 9 Nov 2018 12:00:06 +0000 (12:00 +0000)
When we are proxying a DOMMountPoint, we also need to take care
of bridging legacy interfaces on top of MD-SAL interfaces.

This patch refactors DOM{Notification,Rpc}Router to factor out
DOM{Notification,Rpc}Service adapters and creates DOMActionService
adapter. These are then used in DOMMountPointAdapter, which in
turn is used by DOMMountPointServiceImpl.

This deals with the case when an MD-SAL-registered mount point
is accessed via Controller APIs.

JIRA: CONTROLLER-1869
Change-Id: Ide4c636afdbd13e233880ab616aec52e46ea115f
Signed-off-by: Jakub Morvay <jmorvay@frinx.io>
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMNotificationRouter.java
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMRpcRouter.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-compat/src/main/java/org/opendaylight/controller/sal/core/compat/DOMMountPointAdapter.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-compat/src/main/java/org/opendaylight/controller/sal/core/compat/LegacyDOMActionServiceAdapter.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-compat/src/main/java/org/opendaylight/controller/sal/core/compat/LegacyDOMNotificationServiceAdapter.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-compat/src/main/java/org/opendaylight/controller/sal/core/compat/LegacyDOMRpcServiceAdapter.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-compat/src/main/java/org/opendaylight/controller/sal/core/compat/RpcAvailabilityListenerAdapter.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-compat/src/test/java/org/opendaylight/controller/sal/core/compat/DOMMountPointAdapterTest.java [new file with mode: 0644]

index b5371fc289dd0a4cacf0195becb70d849557d13c..c2cf65c469a2df303a398cf3e1cd65d798b28f7e 100644 (file)
@@ -9,21 +9,16 @@ package org.opendaylight.controller.md.sal.dom.broker.impl;
 
 import com.google.common.util.concurrent.ListenableFuture;
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
-import java.time.Instant;
-import java.util.Arrays;
 import java.util.Collection;
-import java.util.Date;
 import java.util.concurrent.TimeUnit;
-import org.opendaylight.controller.md.sal.dom.api.DOMEvent;
 import org.opendaylight.controller.md.sal.dom.api.DOMNotification;
 import org.opendaylight.controller.md.sal.dom.api.DOMNotificationListener;
 import org.opendaylight.controller.md.sal.dom.api.DOMNotificationPublishService;
 import org.opendaylight.controller.md.sal.dom.api.DOMNotificationService;
 import org.opendaylight.controller.md.sal.dom.spi.DOMNotificationSubscriptionListener;
 import org.opendaylight.controller.md.sal.dom.spi.DOMNotificationSubscriptionListenerRegistry;
-import org.opendaylight.yangtools.concepts.AbstractListenerRegistration;
+import org.opendaylight.controller.sal.core.compat.LegacyDOMNotificationServiceAdapter;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
-import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
 
 /**
@@ -44,18 +39,17 @@ import org.opendaylight.yangtools.yang.model.api.SchemaPath;
  * is realized by arming a background wakeup interrupt.
  */
 @SuppressFBWarnings(value = "NP_NONNULL_PARAM_VIOLATION", justification = "Void is the only allowed value")
-public final class DOMNotificationRouter implements AutoCloseable, DOMNotificationPublishService,
-        DOMNotificationService, DOMNotificationSubscriptionListenerRegistry {
+public final class DOMNotificationRouter extends LegacyDOMNotificationServiceAdapter implements AutoCloseable,
+        DOMNotificationPublishService, DOMNotificationSubscriptionListenerRegistry {
 
-    private final org.opendaylight.mdsal.dom.api.DOMNotificationService delegateNotificationService;
     private final org.opendaylight.mdsal.dom.api.DOMNotificationPublishService delegateNotificationPublishService;
     private final org.opendaylight.mdsal.dom.spi.DOMNotificationSubscriptionListenerRegistry delegateListenerRegistry;
 
     private DOMNotificationRouter(
-            org.opendaylight.mdsal.dom.api.DOMNotificationService delegateNotificationService,
-            org.opendaylight.mdsal.dom.api.DOMNotificationPublishService delegateNotificationPublishService,
-            org.opendaylight.mdsal.dom.spi.DOMNotificationSubscriptionListenerRegistry delegateListenerRegistry) {
-        this.delegateNotificationService = delegateNotificationService;
+            final org.opendaylight.mdsal.dom.api.DOMNotificationService delegateNotificationService,
+            final org.opendaylight.mdsal.dom.api.DOMNotificationPublishService delegateNotificationPublishService,
+            final org.opendaylight.mdsal.dom.spi.DOMNotificationSubscriptionListenerRegistry delegateListenerRegistry) {
+        super(delegateNotificationService);
         this.delegateNotificationPublishService = delegateNotificationPublishService;
         this.delegateListenerRegistry = delegateListenerRegistry;
     }
@@ -84,36 +78,7 @@ public final class DOMNotificationRouter implements AutoCloseable, DOMNotificati
     @Override
     public synchronized <T extends DOMNotificationListener> ListenerRegistration<T> registerNotificationListener(
             final T listener, final Collection<SchemaPath> types) {
-        org.opendaylight.mdsal.dom.api.DOMNotificationListener delegateListener = notification -> {
-            if (notification instanceof DOMNotification) {
-                listener.onNotification((DOMNotification)notification);
-                return;
-            }
-
-            if (notification instanceof org.opendaylight.mdsal.dom.api.DOMEvent) {
-                listener.onNotification(new DefaultDOMEvent(notification,
-                        (org.opendaylight.mdsal.dom.api.DOMEvent)notification));
-                return;
-            }
-
-            listener.onNotification(new DefaultDOMNotification(notification));
-        };
-
-        final ListenerRegistration<org.opendaylight.mdsal.dom.api.DOMNotificationListener> reg =
-                delegateNotificationService.registerNotificationListener(delegateListener, types);
-
-        return new AbstractListenerRegistration<T>(listener) {
-            @Override
-            protected void removeRegistration() {
-                reg.close();
-            }
-        };
-    }
-
-    @Override
-    public <T extends DOMNotificationListener> ListenerRegistration<T> registerNotificationListener(final T listener,
-            final SchemaPath... types) {
-        return registerNotificationListener(listener, Arrays.asList(types));
+        return super.registerNotificationListener(listener, types);
     }
 
     @Override
@@ -141,40 +106,4 @@ public final class DOMNotificationRouter implements AutoCloseable, DOMNotificati
     @Override
     public void close() {
     }
-
-    private static class DefaultDOMNotification implements DOMNotification {
-        private final SchemaPath schemaPath;
-        private final ContainerNode body;
-
-        DefaultDOMNotification(org.opendaylight.mdsal.dom.api.DOMNotification from) {
-            this.schemaPath = from.getType();
-            this.body = from.getBody();
-        }
-
-        @Override
-        public SchemaPath getType() {
-            return schemaPath;
-        }
-
-        @Override
-        public ContainerNode getBody() {
-            return body;
-        }
-    }
-
-    private static class DefaultDOMEvent extends DefaultDOMNotification implements DOMEvent {
-        private final Date eventTime;
-
-        DefaultDOMEvent(org.opendaylight.mdsal.dom.api.DOMNotification fromNotification,
-                org.opendaylight.mdsal.dom.api.DOMEvent fromEvent) {
-            super(fromNotification);
-            final Instant eventInstant = fromEvent.getEventInstant();
-            this.eventTime = eventInstant != null ? Date.from(eventInstant) : null;
-        }
-
-        @Override
-        public Date getEventTime() {
-            return eventTime;
-        }
-    }
 }
index d78e9b9c7b45992726eccbea8b9d079d3b02629e..87ba273bbc713236b7dc3ece38da0089a5e06545 100644 (file)
@@ -11,7 +11,6 @@ import com.google.common.annotations.VisibleForTesting;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.util.concurrent.CheckedFuture;
 import com.google.common.util.concurrent.FluentFuture;
-import java.util.Collection;
 import java.util.Collections;
 import java.util.Map;
 import java.util.Set;
@@ -28,6 +27,7 @@ import org.opendaylight.controller.md.sal.dom.api.DOMRpcService;
 import org.opendaylight.controller.md.sal.dom.spi.AbstractDOMRpcImplementationRegistration;
 import org.opendaylight.controller.sal.core.compat.LegacyDOMRpcResultFutureAdapter;
 import org.opendaylight.controller.sal.core.compat.MdsalDOMRpcResultFutureAdapter;
+import org.opendaylight.controller.sal.core.compat.RpcAvailabilityListenerAdapter;
 import org.opendaylight.yangtools.concepts.AbstractListenerRegistration;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
@@ -77,7 +77,7 @@ public final class DOMRpcRouter implements AutoCloseable, DOMRpcService, DOMRpcP
             new org.opendaylight.mdsal.dom.api.DOMRpcImplementation() {
                 @Override
                 public FluentFuture<org.opendaylight.mdsal.dom.api.DOMRpcResult> invokeRpc(
-                        org.opendaylight.mdsal.dom.api.DOMRpcIdentifier rpc, NormalizedNode<?, ?> input) {
+                        final org.opendaylight.mdsal.dom.api.DOMRpcIdentifier rpc, final NormalizedNode<?, ?> input) {
                     return new MdsalDOMRpcResultFutureAdapter(implementation.invokeRpc(convert(rpc), input));
                 }
 
@@ -103,19 +103,14 @@ public final class DOMRpcRouter implements AutoCloseable, DOMRpcService, DOMRpcP
         };
     }
 
-    private static org.opendaylight.mdsal.dom.api.DOMRpcIdentifier convert(DOMRpcIdentifier from) {
+    private static org.opendaylight.mdsal.dom.api.DOMRpcIdentifier convert(final DOMRpcIdentifier from) {
         return org.opendaylight.mdsal.dom.api.DOMRpcIdentifier.create(from.getType(), from.getContextReference());
     }
 
-    private static DOMRpcIdentifier convert(org.opendaylight.mdsal.dom.api.DOMRpcIdentifier from) {
+    private static DOMRpcIdentifier convert(final org.opendaylight.mdsal.dom.api.DOMRpcIdentifier from) {
         return DOMRpcIdentifier.create(from.getType(), from.getContextReference());
     }
 
-    private static Collection<DOMRpcIdentifier> convert(
-            Collection<org.opendaylight.mdsal.dom.api.DOMRpcIdentifier> from) {
-        return from.stream().map(DOMRpcRouter::convert).collect(Collectors.toList());
-    }
-
     @Override
     public CheckedFuture<DOMRpcResult, DOMRpcException> invokeRpc(final SchemaPath type,
                                                                   final NormalizedNode<?, ?> input) {
@@ -129,17 +124,7 @@ public final class DOMRpcRouter implements AutoCloseable, DOMRpcService, DOMRpcP
     public synchronized <T extends DOMRpcAvailabilityListener> ListenerRegistration<T> registerRpcListener(
             final T listener) {
         final ListenerRegistration<org.opendaylight.mdsal.dom.api.DOMRpcAvailabilityListener> reg =
-            delegateRpcService.registerRpcListener(new org.opendaylight.mdsal.dom.api.DOMRpcAvailabilityListener() {
-                @Override
-                public void onRpcAvailable(Collection<org.opendaylight.mdsal.dom.api.DOMRpcIdentifier> rpcs) {
-                    listener.onRpcAvailable(convert(rpcs));
-                }
-
-                @Override
-                public void onRpcUnavailable(Collection<org.opendaylight.mdsal.dom.api.DOMRpcIdentifier> rpcs) {
-                    listener.onRpcUnavailable(convert(rpcs));
-                }
-
+            delegateRpcService.registerRpcListener(new RpcAvailabilityListenerAdapter<T>(listener) {
                 @Override
                 public boolean acceptsImplementation(final org.opendaylight.mdsal.dom.api.DOMRpcImplementation impl) {
                     // If the DOMRpcImplementation wasn't registered thru this interface then the mapping won't be
@@ -147,7 +132,7 @@ public final class DOMRpcRouter implements AutoCloseable, DOMRpcService, DOMRpcP
                     // behavior. This should be fine since a legacy listener would not be aware of implementation types
                     // registered via the new mdsal API.
                     final DOMRpcImplementation legacyImpl = implMapping.get(impl);
-                    return legacyImpl != null ? listener.acceptsImplementation(legacyImpl) : true;
+                    return legacyImpl != null ? delegate().acceptsImplementation(legacyImpl) : true;
                 }
             });
 
index bc46b6db3b0ad990ce4e179982cbe172b0651ce7..27a4a78b73899361e7d6086069a0848251491e5d 100644 (file)
@@ -5,7 +5,6 @@
  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
  * and is available at http://www.eclipse.org/legal/epl-v10.html
  */
-
 package org.opendaylight.controller.md.sal.dom.broker.impl.mount;
 
 import com.google.common.annotations.VisibleForTesting;
@@ -17,6 +16,7 @@ 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.spi.mount.SimpleDOMMountPoint;
+import org.opendaylight.controller.sal.core.compat.DOMMountPointAdapter;
 import org.opendaylight.mdsal.dom.api.DOMMountPointListener;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
 import org.opendaylight.yangtools.concepts.ObjectRegistration;
@@ -24,7 +24,6 @@ import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 
 public class DOMMountPointServiceImpl implements DOMMountPointService {
-
     private final org.opendaylight.mdsal.dom.api.DOMMountPointService delegate;
 
     @VisibleForTesting
@@ -38,45 +37,7 @@ public class DOMMountPointServiceImpl implements DOMMountPointService {
 
     @Override
     public Optional<DOMMountPoint> getMountPoint(final YangInstanceIdentifier path) {
-        return Optional.fromJavaUtil(delegate.getMountPoint(path).map(DOMMountPointServiceImpl::convert));
-    }
-
-    private static DOMMountPoint convert(final org.opendaylight.mdsal.dom.api.DOMMountPoint from) {
-        return new DOMMountPoint() {
-            @Override
-            public YangInstanceIdentifier getIdentifier() {
-                return from.getIdentifier();
-            }
-
-            @Override
-            public <T extends DOMService> Optional<T> getService(final Class<T> cls) {
-                return Optional.fromJavaUtil(from.getService(cls));
-            }
-
-            @Override
-            public SchemaContext getSchemaContext() {
-                return from.getSchemaContext();
-            }
-
-            @Override
-            public int hashCode() {
-                return from.getIdentifier().hashCode();
-            }
-
-            @Override
-            public boolean equals(final Object obj) {
-                if (this == obj) {
-                    return true;
-                }
-
-                if (!(obj instanceof DOMMountPoint)) {
-                    return false;
-                }
-
-                DOMMountPoint other = (DOMMountPoint) obj;
-                return from.getIdentifier().equals(other.getIdentifier());
-            }
-        };
+        return Optional.fromJavaUtil(delegate.getMountPoint(path).map(DOMMountPointAdapter::new));
     }
 
     @Override
diff --git a/opendaylight/md-sal/sal-dom-compat/src/main/java/org/opendaylight/controller/sal/core/compat/DOMMountPointAdapter.java b/opendaylight/md-sal/sal-dom-compat/src/main/java/org/opendaylight/controller/sal/core/compat/DOMMountPointAdapter.java
new file mode 100644 (file)
index 0000000..b780914
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2018 Pantheon Technologies, s.r.o. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.core.compat;
+
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.base.Optional;
+import com.google.common.collect.ForwardingObject;
+import com.google.common.collect.ImmutableMap;
+import java.util.Map;
+import org.eclipse.jdt.annotation.Nullable;
+import org.opendaylight.controller.md.sal.dom.api.DOMActionService;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
+import org.opendaylight.controller.md.sal.dom.api.DOMMountPoint;
+import org.opendaylight.controller.md.sal.dom.api.DOMNotificationService;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcService;
+import org.opendaylight.controller.md.sal.dom.api.DOMService;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+
+/**
+ * Adapter providing Controller DOMMountPoint implementation based on an MD-SAL DOMMountPoint delegate. Services are
+ * looked up in the delegate first. If a lookup is unsuccessful, this class attempts to transparently proxy well-known
+ * Controller DOMServices on top of their MD-SAL counterparts available from delegate.
+ */
+@Deprecated
+public class DOMMountPointAdapter extends ForwardingObject implements DOMMountPoint {
+    private abstract static class CompatFactory<M extends org.opendaylight.mdsal.dom.api.DOMService,
+            C extends DOMService> {
+        private final Class<M> mdsalClass;
+
+        CompatFactory(final Class<M> mdsalClass) {
+            this.mdsalClass = requireNonNull(mdsalClass);
+        }
+
+        final @Nullable C createService(final org.opendaylight.mdsal.dom.api.DOMMountPoint mountPoint) {
+            return mountPoint.getService(mdsalClass).map(this::createService).orElse(null);
+        }
+
+        abstract C createService(M delegate);
+    }
+
+    private static final Map<Class<? extends DOMService>, CompatFactory<?, ?>> KNOWN_SERVICES = ImmutableMap.of(
+        DOMActionService.class, new CompatFactory<org.opendaylight.mdsal.dom.api.DOMActionService, DOMActionService>(
+                org.opendaylight.mdsal.dom.api.DOMActionService.class) {
+            @Override
+            DOMActionService createService(final org.opendaylight.mdsal.dom.api.DOMActionService delegate) {
+                return new LegacyDOMActionServiceAdapter(delegate);
+            }
+        },
+        DOMDataBroker.class, new CompatFactory<org.opendaylight.mdsal.dom.api.DOMDataBroker, DOMDataBroker>(
+                org.opendaylight.mdsal.dom.api.DOMDataBroker.class) {
+            @Override
+            DOMDataBroker createService(final org.opendaylight.mdsal.dom.api.DOMDataBroker delegate) {
+                return new LegacyDOMDataBrokerAdapter(delegate);
+            }
+        },
+        DOMNotificationService.class, new CompatFactory<org.opendaylight.mdsal.dom.api.DOMNotificationService,
+                DOMNotificationService>(org.opendaylight.mdsal.dom.api.DOMNotificationService.class) {
+            @Override
+            DOMNotificationService createService(final org.opendaylight.mdsal.dom.api.DOMNotificationService delegate) {
+                return new LegacyDOMNotificationServiceAdapter(delegate);
+            }
+        },
+        DOMRpcService.class, new CompatFactory<org.opendaylight.mdsal.dom.api.DOMRpcService, DOMRpcService>(
+                org.opendaylight.mdsal.dom.api.DOMRpcService.class) {
+            @Override
+            DOMRpcService createService(final org.opendaylight.mdsal.dom.api.DOMRpcService delegate) {
+                return new LegacyDOMRpcServiceAdapter(delegate);
+            }
+        });
+
+    private final org.opendaylight.mdsal.dom.api.DOMMountPoint delegate;
+
+    public DOMMountPointAdapter(final org.opendaylight.mdsal.dom.api.DOMMountPoint delegate) {
+        this.delegate = requireNonNull(delegate);
+    }
+
+    @Override
+    public YangInstanceIdentifier getIdentifier() {
+        return delegate().getIdentifier();
+    }
+
+    @Override
+    public <T extends DOMService> Optional<T> getService(final Class<T> cls) {
+        final java.util.Optional<T> found = delegate.getService(cls);
+        if (found.isPresent()) {
+            return Optional.of(found.get());
+        }
+
+        final CompatFactory<?, ?> compat = KNOWN_SERVICES.get(cls);
+        return Optional.fromNullable(cls.cast(compat == null ? null : compat.createService(delegate)));
+    }
+
+    @Override
+    public SchemaContext getSchemaContext() {
+        return delegate().getSchemaContext();
+    }
+
+    @Override
+    public int hashCode() {
+        return getIdentifier().hashCode();
+    }
+
+    @Override
+    public boolean equals(final Object obj) {
+        if (this == obj) {
+            return true;
+        }
+
+        if (!(obj instanceof DOMMountPoint)) {
+            return false;
+        }
+
+        DOMMountPoint other = (DOMMountPoint) obj;
+        return getIdentifier().equals(other.getIdentifier());
+    }
+
+    @Override
+    protected org.opendaylight.mdsal.dom.api.DOMMountPoint delegate() {
+        return delegate;
+    }
+}
diff --git a/opendaylight/md-sal/sal-dom-compat/src/main/java/org/opendaylight/controller/sal/core/compat/LegacyDOMActionServiceAdapter.java b/opendaylight/md-sal/sal-dom-compat/src/main/java/org/opendaylight/controller/sal/core/compat/LegacyDOMActionServiceAdapter.java
new file mode 100644 (file)
index 0000000..8331bad
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2018 Pantheon Technologies, s.r.o. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.core.compat;
+
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.collect.ClassToInstanceMap;
+import com.google.common.collect.ForwardingObject;
+import com.google.common.util.concurrent.FluentFuture;
+import org.opendaylight.controller.md.sal.dom.api.DOMActionService;
+import org.opendaylight.mdsal.dom.api.DOMActionResult;
+import org.opendaylight.mdsal.dom.api.DOMActionServiceExtension;
+import org.opendaylight.mdsal.dom.api.DOMDataTreeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+
+@Deprecated
+public class LegacyDOMActionServiceAdapter extends ForwardingObject implements DOMActionService {
+    private final org.opendaylight.mdsal.dom.api.DOMActionService delegate;
+
+    public LegacyDOMActionServiceAdapter(final org.opendaylight.mdsal.dom.api.DOMActionService delegate) {
+        this.delegate = requireNonNull(delegate);
+    }
+
+    @Override
+    protected org.opendaylight.mdsal.dom.api.DOMActionService delegate() {
+        return delegate;
+    }
+
+    @Override
+    public FluentFuture<? extends DOMActionResult> invokeAction(final SchemaPath type, final DOMDataTreeIdentifier path,
+            final ContainerNode input) {
+        return delegate.invokeAction(type, path, input);
+    }
+
+    @Override
+    public ClassToInstanceMap<DOMActionServiceExtension> getExtensions() {
+        return delegate.getExtensions();
+    }
+}
diff --git a/opendaylight/md-sal/sal-dom-compat/src/main/java/org/opendaylight/controller/sal/core/compat/LegacyDOMNotificationServiceAdapter.java b/opendaylight/md-sal/sal-dom-compat/src/main/java/org/opendaylight/controller/sal/core/compat/LegacyDOMNotificationServiceAdapter.java
new file mode 100644 (file)
index 0000000..293fcb3
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2018 Pantheon Technologies, s.r.o. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.core.compat;
+
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.collect.ForwardingObject;
+import java.time.Instant;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Date;
+import org.opendaylight.controller.md.sal.dom.api.DOMEvent;
+import org.opendaylight.controller.md.sal.dom.api.DOMNotification;
+import org.opendaylight.controller.md.sal.dom.api.DOMNotificationListener;
+import org.opendaylight.controller.md.sal.dom.api.DOMNotificationService;
+import org.opendaylight.yangtools.concepts.AbstractListenerRegistration;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+
+@Deprecated
+public class LegacyDOMNotificationServiceAdapter extends ForwardingObject implements DOMNotificationService {
+    private final org.opendaylight.mdsal.dom.api.DOMNotificationService delegate;
+
+    public LegacyDOMNotificationServiceAdapter(final org.opendaylight.mdsal.dom.api.DOMNotificationService delegate) {
+        this.delegate = requireNonNull(delegate);
+    }
+
+    @Override
+    public <T extends DOMNotificationListener> ListenerRegistration<T> registerNotificationListener(final T listener,
+            final Collection<SchemaPath> types) {
+        final ListenerRegistration<org.opendaylight.mdsal.dom.api.DOMNotificationListener> reg =
+                delegate().registerNotificationListener(notification -> {
+                    if (notification instanceof DOMNotification) {
+                        listener.onNotification((DOMNotification)notification);
+                        return;
+                    }
+
+                    if (notification instanceof org.opendaylight.mdsal.dom.api.DOMEvent) {
+                        listener.onNotification(new DefaultDOMEvent(notification,
+                            (org.opendaylight.mdsal.dom.api.DOMEvent)notification));
+                        return;
+                    }
+
+                    listener.onNotification(new DefaultDOMNotification(notification));
+                }, types);
+
+        return new AbstractListenerRegistration<T>(listener) {
+            @Override
+            protected void removeRegistration() {
+                reg.close();
+            }
+        };
+    }
+
+    @Override
+    public <T extends DOMNotificationListener> ListenerRegistration<T> registerNotificationListener(final T listener,
+            final SchemaPath... types) {
+        return registerNotificationListener(listener, Arrays.asList(types));
+    }
+
+    @Override
+    protected org.opendaylight.mdsal.dom.api.DOMNotificationService delegate() {
+        return delegate;
+    }
+
+    private static class DefaultDOMNotification implements DOMNotification {
+        private final org.opendaylight.mdsal.dom.api.DOMNotification delegate;
+
+        DefaultDOMNotification(final org.opendaylight.mdsal.dom.api.DOMNotification delegate) {
+            this.delegate = requireNonNull(delegate);
+        }
+
+        @Override
+        public SchemaPath getType() {
+            return delegate.getType();
+        }
+
+        @Override
+        public ContainerNode getBody() {
+            return delegate.getBody();
+        }
+    }
+
+    private static class DefaultDOMEvent extends DefaultDOMNotification implements DOMEvent {
+        private final Date eventTime;
+
+        DefaultDOMEvent(final org.opendaylight.mdsal.dom.api.DOMNotification fromNotification,
+                final org.opendaylight.mdsal.dom.api.DOMEvent fromEvent) {
+            super(fromNotification);
+            final Instant eventInstant = fromEvent.getEventInstant();
+            this.eventTime = eventInstant != null ? Date.from(eventInstant) : null;
+        }
+
+        @Override
+        public Date getEventTime() {
+            return eventTime;
+        }
+    }
+}
diff --git a/opendaylight/md-sal/sal-dom-compat/src/main/java/org/opendaylight/controller/sal/core/compat/LegacyDOMRpcServiceAdapter.java b/opendaylight/md-sal/sal-dom-compat/src/main/java/org/opendaylight/controller/sal/core/compat/LegacyDOMRpcServiceAdapter.java
new file mode 100644 (file)
index 0000000..170d9c9
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2018 Pantheon Technologies, s.r.o. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.core.compat;
+
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.collect.ForwardingObject;
+import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.FluentFuture;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcAvailabilityListener;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcException;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcResult;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcService;
+import org.opendaylight.yangtools.concepts.AbstractListenerRegistration;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+
+@Deprecated
+public class LegacyDOMRpcServiceAdapter extends ForwardingObject implements DOMRpcService {
+    private final org.opendaylight.mdsal.dom.api.DOMRpcService delegate;
+
+    public LegacyDOMRpcServiceAdapter(final org.opendaylight.mdsal.dom.api.DOMRpcService delegate) {
+        this.delegate = requireNonNull(delegate);
+    }
+
+    @Override
+    public CheckedFuture<DOMRpcResult, DOMRpcException> invokeRpc(final SchemaPath type,
+                                                                  final NormalizedNode<?, ?> input) {
+        final FluentFuture<org.opendaylight.mdsal.dom.api.DOMRpcResult> future = delegate().invokeRpc(type, input);
+        return future instanceof MdsalDOMRpcResultFutureAdapter ? ((MdsalDOMRpcResultFutureAdapter)future).delegate()
+                : new LegacyDOMRpcResultFutureAdapter(future);
+    }
+
+    @Override
+    public <T extends DOMRpcAvailabilityListener> ListenerRegistration<T> registerRpcListener(final T listener) {
+        final ListenerRegistration<org.opendaylight.mdsal.dom.api.DOMRpcAvailabilityListener> reg =
+            delegate().registerRpcListener(new RpcAvailabilityListenerAdapter<>(listener));
+
+        return new AbstractListenerRegistration<T>(listener) {
+            @Override
+            protected void removeRegistration() {
+                reg.close();
+            }
+        };
+    }
+
+    @Override
+    protected org.opendaylight.mdsal.dom.api.DOMRpcService delegate() {
+        return delegate;
+    }
+}
diff --git a/opendaylight/md-sal/sal-dom-compat/src/main/java/org/opendaylight/controller/sal/core/compat/RpcAvailabilityListenerAdapter.java b/opendaylight/md-sal/sal-dom-compat/src/main/java/org/opendaylight/controller/sal/core/compat/RpcAvailabilityListenerAdapter.java
new file mode 100644 (file)
index 0000000..d5d472a
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2018 Pantheon Technologies, s.r.o. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.core.compat;
+
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.collect.ForwardingObject;
+import java.util.Collection;
+import java.util.stream.Collectors;
+import org.eclipse.jdt.annotation.NonNull;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcAvailabilityListener;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcIdentifier;
+
+@Deprecated
+public class RpcAvailabilityListenerAdapter<T extends DOMRpcAvailabilityListener> extends ForwardingObject
+        implements org.opendaylight.mdsal.dom.api.DOMRpcAvailabilityListener {
+    private final @NonNull T delegate;
+
+    public RpcAvailabilityListenerAdapter(final T delegate) {
+        this.delegate = requireNonNull(delegate);
+    }
+
+    @Override
+    public void onRpcAvailable(final Collection<org.opendaylight.mdsal.dom.api.DOMRpcIdentifier> rpcs) {
+        delegate.onRpcAvailable(convert(rpcs));
+    }
+
+    @Override
+    public void onRpcUnavailable(final Collection<org.opendaylight.mdsal.dom.api.DOMRpcIdentifier> rpcs) {
+        delegate.onRpcUnavailable(convert(rpcs));
+    }
+
+    @Override
+    protected T delegate() {
+        return delegate;
+    }
+
+    private static @NonNull Collection<DOMRpcIdentifier> convert(
+            final Collection<org.opendaylight.mdsal.dom.api.DOMRpcIdentifier> from) {
+        return from.stream().map(RpcAvailabilityListenerAdapter::convert).collect(Collectors.toList());
+    }
+
+    private static @NonNull DOMRpcIdentifier convert(final org.opendaylight.mdsal.dom.api.DOMRpcIdentifier from) {
+        return DOMRpcIdentifier.create(from.getType(), from.getContextReference());
+    }
+}
diff --git a/opendaylight/md-sal/sal-dom-compat/src/test/java/org/opendaylight/controller/sal/core/compat/DOMMountPointAdapterTest.java b/opendaylight/md-sal/sal-dom-compat/src/test/java/org/opendaylight/controller/sal/core/compat/DOMMountPointAdapterTest.java
new file mode 100644 (file)
index 0000000..4c57f1c
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2018 Pantheon Technologies, s.r.o. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.core.compat;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+
+import com.google.common.collect.ImmutableClassToInstanceMap;
+import java.util.Optional;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.opendaylight.controller.md.sal.dom.api.DOMActionService;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
+import org.opendaylight.controller.md.sal.dom.api.DOMNotificationService;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcService;
+import org.opendaylight.mdsal.dom.api.DOMMountPoint;
+
+@Deprecated
+@RunWith(MockitoJUnitRunner.StrictStubs.class)
+public class DOMMountPointAdapterTest {
+    @Mock
+    private DOMMountPoint delegate;
+
+    private DOMMountPointAdapter adapter;
+
+    @Before
+    public void before() {
+        doReturn(Optional.empty()).when(delegate).getService(any());
+        adapter = new DOMMountPointAdapter(delegate);
+    }
+
+    @Test
+    public void testDOMActionService() {
+        assertFalse(adapter.getService(DOMActionService.class).isPresent());
+
+        org.opendaylight.mdsal.dom.api.DOMActionService mdsal =
+                mock(org.opendaylight.mdsal.dom.api.DOMActionService.class);
+
+        doReturn(Optional.of(mdsal)).when(delegate).getService(org.opendaylight.mdsal.dom.api.DOMActionService.class);
+        assertTrue(adapter.getService(DOMActionService.class).isPresent());
+    }
+
+    @Test
+    public void testDOMDataBroker() {
+        assertFalse(adapter.getService(DOMDataBroker.class).isPresent());
+
+        org.opendaylight.mdsal.dom.api.DOMDataBroker mdsal = mock(org.opendaylight.mdsal.dom.api.DOMDataBroker.class);
+        doReturn(ImmutableClassToInstanceMap.of()).when(mdsal).getExtensions();
+
+        doReturn(Optional.of(mdsal)).when(delegate).getService(org.opendaylight.mdsal.dom.api.DOMDataBroker.class);
+        assertTrue(adapter.getService(DOMDataBroker.class).isPresent());
+    }
+
+    @Test
+    public void testDOMNotificationService() {
+        assertFalse(adapter.getService(DOMNotificationService.class).isPresent());
+
+        org.opendaylight.mdsal.dom.api.DOMNotificationService mdsal =
+                mock(org.opendaylight.mdsal.dom.api.DOMNotificationService.class);
+
+        doReturn(Optional.of(mdsal)).when(delegate).getService(
+            org.opendaylight.mdsal.dom.api.DOMNotificationService.class);
+        assertTrue(adapter.getService(DOMNotificationService.class).isPresent());
+    }
+
+    @Test
+    public void testDOMRpcService() {
+        assertFalse(adapter.getService(DOMRpcService.class).isPresent());
+
+        org.opendaylight.mdsal.dom.api.DOMRpcService mdsal = mock(org.opendaylight.mdsal.dom.api.DOMRpcService.class);
+
+        doReturn(Optional.of(mdsal)).when(delegate).getService(org.opendaylight.mdsal.dom.api.DOMRpcService.class);
+        assertTrue(adapter.getService(DOMRpcService.class).isPresent());
+    }
+}