Add ActionProviderService adapter 65/74065/13
authorRobert Varga <robert.varga@pantheon.tech>
Mon, 16 Jul 2018 12:41:01 +0000 (14:41 +0200)
committerRobert Varga <nite@hq.sk>
Sat, 28 Jul 2018 08:33:21 +0000 (08:33 +0000)
A mostly straightforward implementation of ActionProviderService on top
of a DOMOperationProviderService.

Change-Id: I50b7f2d7b03059088be9ba277999c11bc085b385
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/ActionProviderServiceAdapter.java [new file with mode: 0644]
binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/BindingAdapterFactory.java
binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/BindingOperationFluentFuture.java [new file with mode: 0644]
binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/osgi/DynamicBindingAdapter.java
binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/spi/AdapterFactory.java

diff --git a/binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/ActionProviderServiceAdapter.java b/binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/ActionProviderServiceAdapter.java
new file mode 100644 (file)
index 0000000..11bc55d
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * 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.mdsal.binding.dom.adapter;
+
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.annotations.Beta;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.util.concurrent.FluentFuture;
+import java.util.Set;
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.opendaylight.mdsal.binding.api.ActionProviderService;
+import org.opendaylight.mdsal.binding.api.DataTreeIdentifier;
+import org.opendaylight.mdsal.binding.dom.codec.api.BindingNormalizedNodeSerializer;
+import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
+import org.opendaylight.mdsal.dom.api.DOMActionImplementation;
+import org.opendaylight.mdsal.dom.api.DOMActionProviderService;
+import org.opendaylight.mdsal.dom.api.DOMActionResult;
+import org.opendaylight.mdsal.dom.api.DOMDataTreeIdentifier;
+import org.opendaylight.yangtools.concepts.AbstractObjectRegistration;
+import org.opendaylight.yangtools.concepts.ObjectRegistration;
+import org.opendaylight.yangtools.yang.binding.Action;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.common.YangConstants;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+
+@Beta
+@NonNullByDefault
+final class ActionProviderServiceAdapter extends AbstractBindingAdapter<DOMActionProviderService>
+        implements ActionProviderService {
+    ActionProviderServiceAdapter(final BindingToNormalizedNodeCodec codec, final DOMActionProviderService delegate) {
+        super(codec, delegate);
+    }
+
+    @Override
+    public <O extends DataObject, P extends InstanceIdentifier<O>,
+        T extends org.opendaylight.yangtools.yang.binding.Action<P, ?, ?>, S extends T>
+        ObjectRegistration<S> registerImplementation(final Class<T> actionInterface, final S implementation,
+                final LogicalDatastoreType datastore, final Set<DataTreeIdentifier<O>> validNodes) {
+        final SchemaPath path = getCodec().getActionPath(actionInterface);
+        final ObjectRegistration<DOMActionImplementation> reg = getDelegate().registerActionImplementation(
+            new Impl(getCodec(),
+                NodeIdentifier.create(YangConstants.operationOutputQName(path.getLastComponent().getModule())),
+                actionInterface, implementation), ImmutableSet.of());
+        return new AbstractObjectRegistration<S>(implementation) {
+            @Override
+            protected void removeRegistration() {
+                reg.close();
+            }
+        };
+    }
+
+    private static final class Impl implements DOMActionImplementation {
+        private final Class<? extends Action<?, ?, ?>> actionInterface;
+        private final Action implementation;
+        private final BindingNormalizedNodeSerializer codec;
+        private final NodeIdentifier outputName;
+
+        Impl(final BindingNormalizedNodeSerializer codec, final NodeIdentifier outputName,
+                final Class<? extends Action<?, ?, ?>> actionInterface, final Action<?, ?, ?> implementation) {
+            this.codec = requireNonNull(codec);
+            this.outputName = requireNonNull(outputName);
+            this.actionInterface = requireNonNull(actionInterface);
+            this.implementation = requireNonNull(implementation);
+        }
+
+        @Override
+        @SuppressWarnings({ "rawtypes", "unchecked" })
+        public FluentFuture<? extends DOMActionResult> invokeAction(final SchemaPath type,
+                final DOMDataTreeIdentifier path, final ContainerNode input) {
+            final FluentFuture<RpcResult<?>> userFuture = implementation.invoke(
+                codec.fromYangInstanceIdentifier(path.getRootIdentifier()),
+                codec.fromNormalizedNodeActionInput(actionInterface, input));
+            if (userFuture instanceof BindingOperationFluentFuture) {
+                // If we are looping back through our future we can skip wrapping. This can happen if application
+                // forwards invocations between multiple instantiations of the same action.
+                return (BindingOperationFluentFuture) userFuture;
+            }
+
+            return new BindingOperationFluentFuture(userFuture, actionInterface, outputName, codec);
+        }
+    }
+}
index bd8cc1438249ac8362e54cf0f2eac65203c78504..6af1f8869135910ba1862163120329b39c675a55 100644 (file)
@@ -12,6 +12,7 @@ import static java.util.Objects.requireNonNull;
 import com.google.common.annotations.Beta;
 import javax.annotation.concurrent.ThreadSafe;
 import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.opendaylight.mdsal.binding.api.ActionProviderService;
 import org.opendaylight.mdsal.binding.api.ActionService;
 import org.opendaylight.mdsal.binding.api.DataBroker;
 import org.opendaylight.mdsal.binding.api.DataTreeService;
@@ -21,6 +22,7 @@ import org.opendaylight.mdsal.binding.api.NotificationService;
 import org.opendaylight.mdsal.binding.api.RpcConsumerRegistry;
 import org.opendaylight.mdsal.binding.api.RpcProviderService;
 import org.opendaylight.mdsal.binding.dom.adapter.spi.AdapterFactory;
+import org.opendaylight.mdsal.dom.api.DOMActionProviderService;
 import org.opendaylight.mdsal.dom.api.DOMActionService;
 import org.opendaylight.mdsal.dom.api.DOMDataBroker;
 import org.opendaylight.mdsal.dom.api.DOMDataTreeService;
@@ -133,4 +135,9 @@ public final class BindingAdapterFactory implements AdapterFactory {
     public ActionService createActionService(final DOMActionService domService) {
         return new ActionServiceAdapter(codec, domService);
     }
+
+    @Override
+    public ActionProviderService createActionProviderService(final DOMActionProviderService domService) {
+        return new ActionProviderServiceAdapter(codec, domService);
+    }
 }
diff --git a/binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/BindingOperationFluentFuture.java b/binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/BindingOperationFluentFuture.java
new file mode 100644 (file)
index 0000000..80bbd7e
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * 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.mdsal.binding.dom.adapter;
+
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.util.concurrent.AbstractFuture;
+import com.google.common.util.concurrent.FluentFuture;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.MoreExecutors;
+import java.util.concurrent.ExecutionException;
+import org.opendaylight.mdsal.binding.dom.codec.api.BindingNormalizedNodeSerializer;
+import org.opendaylight.mdsal.dom.api.DOMActionResult;
+import org.opendaylight.mdsal.dom.spi.SimpleDOMActionResult;
+import org.opendaylight.yangtools.yang.binding.Action;
+import org.opendaylight.yangtools.yang.binding.RpcOutput;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+
+final class BindingOperationFluentFuture<O extends RpcOutput> extends AbstractFuture<DOMActionResult>
+        implements BindingRpcFutureAware {
+    private final ListenableFuture<RpcResult<O>> userFuture;
+    private final Class<? extends Action<?, ?, O>> action;
+    private final NodeIdentifier identifier;
+
+    private BindingNormalizedNodeSerializer codec;
+
+    BindingOperationFluentFuture(final FluentFuture<RpcResult<O>> userFuture,
+            final Class<? extends Action<?, ?, O>> action, final NodeIdentifier identifier,
+            final BindingNormalizedNodeSerializer codec) {
+        this.userFuture = requireNonNull(userFuture);
+        this.action = requireNonNull(action);
+        this.identifier = requireNonNull(identifier);
+        this.codec = requireNonNull(codec);
+        userFuture.addListener(this::userFutureCompleted, MoreExecutors.directExecutor());
+    }
+
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    @Override
+    public ListenableFuture<RpcResult<?>> getBindingFuture() {
+        return (ListenableFuture) userFuture;
+    }
+
+    @SuppressWarnings("checkstyle:illegalCatch")
+    private void userFutureCompleted() {
+        final DOMActionResult domResult;
+
+        try {
+            final RpcResult<O> bindingResult = Futures.getDone(userFuture);
+            if (bindingResult.getResult() != null) {
+                domResult = new SimpleDOMActionResult(
+                        codec.toLazyNormalizedNodeActionOutput(action, identifier, bindingResult.getResult()),
+                        bindingResult.getErrors());
+            } else {
+                domResult = new SimpleDOMActionResult(bindingResult.getErrors());
+            }
+        } catch (ExecutionException e) {
+            codec = null;
+            setException(e.getCause());
+            return;
+        } catch (RuntimeException | Error e) {
+            codec = null;
+            setException(e);
+            return;
+        }
+
+        codec = null;
+        set(domResult);
+    }
+}
index 825fda6fdf77bf5d8eeb61fc4d1c7ed584596c0d..939f70c5d75172de8b086a2dafe8978e0d0ad87a 100644 (file)
@@ -10,6 +10,7 @@ package org.opendaylight.mdsal.binding.dom.adapter.osgi;
 import com.google.common.collect.ImmutableList;
 import java.util.List;
 import javax.annotation.concurrent.GuardedBy;
+import org.opendaylight.mdsal.binding.api.ActionProviderService;
 import org.opendaylight.mdsal.binding.api.ActionService;
 import org.opendaylight.mdsal.binding.api.BindingService;
 import org.opendaylight.mdsal.binding.api.DataBroker;
@@ -20,6 +21,7 @@ import org.opendaylight.mdsal.binding.api.NotificationService;
 import org.opendaylight.mdsal.binding.api.RpcConsumerRegistry;
 import org.opendaylight.mdsal.binding.api.RpcProviderService;
 import org.opendaylight.mdsal.binding.dom.adapter.spi.AdapterFactory;
+import org.opendaylight.mdsal.dom.api.DOMActionProviderService;
 import org.opendaylight.mdsal.dom.api.DOMActionService;
 import org.opendaylight.mdsal.dom.api.DOMDataBroker;
 import org.opendaylight.mdsal.dom.api.DOMDataTreeService;
@@ -60,7 +62,9 @@ public final class DynamicBindingAdapter implements AutoCloseable {
                     factory::createRpcConsumerRegistry),
             new AdaptingTracker<>(ctx, DOMRpcProviderService.class, RpcProviderService.class,
                     factory::createRpcProviderService),
-            new AdaptingTracker<>(ctx, DOMActionService.class, ActionService.class, factory::createActionService));
+            new AdaptingTracker<>(ctx, DOMActionService.class, ActionService.class, factory::createActionService),
+            new AdaptingTracker<>(ctx, DOMActionProviderService.class, ActionProviderService.class,
+                factory::createActionProviderService));
 
         LOG.debug("Starting {} DOMService trackers", trackers.size());
         trackers.forEach(ServiceTracker::open);
index 22f7731cdb03f59d31bcddfad737c0f52ac65a72..f6229f3d04d2b302b6b6a80cbda760ece2662957 100644 (file)
@@ -9,6 +9,7 @@ package org.opendaylight.mdsal.binding.dom.adapter.spi;
 
 import com.google.common.annotations.Beta;
 import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.opendaylight.mdsal.binding.api.ActionProviderService;
 import org.opendaylight.mdsal.binding.api.ActionService;
 import org.opendaylight.mdsal.binding.api.BindingService;
 import org.opendaylight.mdsal.binding.api.DataBroker;
@@ -18,6 +19,7 @@ import org.opendaylight.mdsal.binding.api.NotificationPublishService;
 import org.opendaylight.mdsal.binding.api.NotificationService;
 import org.opendaylight.mdsal.binding.api.RpcConsumerRegistry;
 import org.opendaylight.mdsal.binding.api.RpcProviderService;
+import org.opendaylight.mdsal.dom.api.DOMActionProviderService;
 import org.opendaylight.mdsal.dom.api.DOMActionService;
 import org.opendaylight.mdsal.dom.api.DOMDataBroker;
 import org.opendaylight.mdsal.dom.api.DOMDataTreeService;
@@ -85,7 +87,7 @@ public interface AdapterFactory {
      * Create a {@link RpcConsumerRegistry} backed by a {@link DOMRpcService}.
      *
      * @param domService Backing DOMRpcService
-     * @return A RpcConsumerRegistry
+     * @return An RpcConsumerRegistry
      * @throws NullPointerException if {@code domService} is null
      */
     RpcConsumerRegistry createRpcConsumerRegistry(DOMRpcService domService);
@@ -94,7 +96,7 @@ public interface AdapterFactory {
      * Create a {@link RpcProviderService} backed by a {@link DOMRpcProviderService}.
      *
      * @param domService Backing DOMRpcProviderService
-     * @return A RpcProviderService
+     * @return An RpcProviderService
      * @throws NullPointerException if {@code domService} is null
      */
     RpcProviderService createRpcProviderService(DOMRpcProviderService domService);
@@ -103,8 +105,17 @@ public interface AdapterFactory {
      * Create a {@link ActionService} backed by a {@link DOMActionService}.
      *
      * @param domService Backing DOMOperationService
-     * @return A ActionService
+     * @return An ActionService
      * @throws NullPointerException if {@code domService} is null
      */
     ActionService createActionService(DOMActionService domService);
+
+    /**
+     * Create a {@link ActionProviderService} backed by a {@link DOMActionProviderService}.
+     *
+     * @param domService Backing DOMOperationProviderService
+     * @return An ActionProviderService
+     * @throws NullPointerException if {@code domService} is null
+     */
+    ActionProviderService createActionProviderService(DOMActionProviderService domService);
 }