From: Robert Varga Date: Fri, 13 Jul 2018 20:49:53 +0000 (+0200) Subject: Add ActionService adapter X-Git-Tag: release/fluorine~84 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=commitdiff_plain;h=1ad726553156c68d7517190ab6345a4c3b697a71;p=mdsal.git Add ActionService adapter A mostly straightforward implementation of ActionService on top of a DOMOperationService. Change-Id: Ibcfd72f3446b5cad0a3b6ced4852a8e77fd7e652 Signed-off-by: Robert Varga --- diff --git a/binding/mdsal-binding-api/src/main/java/org/opendaylight/mdsal/binding/api/ActionService.java b/binding/mdsal-binding-api/src/main/java/org/opendaylight/mdsal/binding/api/ActionService.java index a82909ecf8..7b272ba101 100644 --- a/binding/mdsal-binding-api/src/main/java/org/opendaylight/mdsal/binding/api/ActionService.java +++ b/binding/mdsal-binding-api/src/main/java/org/opendaylight/mdsal/binding/api/ActionService.java @@ -53,7 +53,7 @@ public interface ActionService extends BindingService { * @throws NullPointerException if {@code actionInterface} is null * @throws IllegalArgumentException when {@code actionInterface} does not conform to the Binding Specification */ - > T getActionHandle(Class actionInterface, + > T getActionHandle(Class actionInterface, Set> validNodes); default > T getActionHandle(final Class actionInterface) { diff --git a/binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/ActionAdapter.java b/binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/ActionAdapter.java new file mode 100644 index 0000000000..ce3703f98a --- /dev/null +++ b/binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/ActionAdapter.java @@ -0,0 +1,87 @@ +/* + * 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 static org.opendaylight.yangtools.yang.common.YangConstants.operationInputQName; + +import com.google.common.util.concurrent.FluentFuture; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.MoreExecutors; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.opendaylight.mdsal.common.api.LogicalDatastoreType; +import org.opendaylight.mdsal.dom.api.DOMDataTreeIdentifier; +import org.opendaylight.mdsal.dom.api.DOMOperationResult; +import org.opendaylight.mdsal.dom.api.DOMOperationService; +import org.opendaylight.yangtools.yang.binding.Action; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.binding.RpcInput; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier; +import org.opendaylight.yangtools.yang.model.api.SchemaPath; + +@NonNullByDefault +final class ActionAdapter extends AbstractBindingAdapter implements InvocationHandler { + private final Class> type; + private final NodeIdentifier inputName; + private final SchemaPath schemaPath; + + ActionAdapter(final BindingToNormalizedNodeCodec codec, final DOMOperationService delegate, + final Class> type) { + super(codec, delegate); + this.type = requireNonNull(type); + this.schemaPath = getCodec().getActionPath(type); + this.inputName = NodeIdentifier.create(operationInputQName(schemaPath.getLastComponent().getModule())); + } + + @Override public @Nullable Object invoke(final @Nullable Object proxy, final @Nullable Method method, + final Object @Nullable [] args) throws Throwable { + switch (method.getName()) { + case "equals": + if (args.length == 1) { + return proxy == args[0]; + } + break; + case "hashCode": + if (args.length == 0) { + return System.identityHashCode(proxy); + } + break; + case "toString": + if (args.length == 0) { + return type.getName() + "$Adapter{delegate=" + getDelegate() + "}"; + } + break; + case "invoke": + if (args.length == 2) { + final InstanceIdentifier path = (InstanceIdentifier) requireNonNull(args[0]); + final RpcInput input = (RpcInput) requireNonNull(args[1]); + final FluentFuture future = getDelegate().invokeAction(schemaPath, + new DOMDataTreeIdentifier(LogicalDatastoreType.OPERATIONAL, getCodec().toNormalized(path)), + getCodec().toLazyNormalizedNodeActionInput(type, inputName, input)); + + // Invocation returned a future we know about -- return that future instead + if (future instanceof BindingRpcFutureAware) { + return ((BindingRpcFutureAware) future).getBindingFuture(); + } + + return Futures.transform(future, + dom -> RpcResultUtil.rpcResultFromDOM(dom.getErrors(), dom.getOutput() + .map(output -> getCodec().fromNormalizedNodeActionOutput(type, output)) + .orElse(null)), MoreExecutors.directExecutor()); + } + break; + default: + break; + } + + throw new NoSuchMethodError("Method " + method.toString() + "is unsupported."); + } +} diff --git a/binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/ActionServiceAdapter.java b/binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/ActionServiceAdapter.java new file mode 100644 index 0000000000..ad85ca1513 --- /dev/null +++ b/binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/ActionServiceAdapter.java @@ -0,0 +1,78 @@ +/* + * 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 com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkState; +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.lang.reflect.Proxy; +import java.util.Set; +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.opendaylight.mdsal.binding.api.ActionService; +import org.opendaylight.mdsal.binding.api.DataTreeIdentifier; +import org.opendaylight.mdsal.dom.api.DOMOperationService; +import org.opendaylight.yangtools.concepts.Delegator; +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.binding.RpcInput; +import org.opendaylight.yangtools.yang.binding.RpcOutput; +import org.opendaylight.yangtools.yang.binding.util.BindingReflections; +import org.opendaylight.yangtools.yang.common.RpcResult; + +@Beta +@NonNullByDefault +final class ActionServiceAdapter + extends AbstractBindingLoadingAdapter>, ActionAdapter> + implements ActionService { + private static final class ConstrainedAction implements Delegator>, + Action { + private final Action delegate; + private final Set> nodes; + + ConstrainedAction(final Action delegate, final Set> nodes) { + this.delegate = requireNonNull((Action) delegate); + this.nodes = requireNonNull(nodes); + } + + @Override + public FluentFuture> invoke(final InstanceIdentifier path, + final RpcInput input) { + checkState(nodes.contains(path), "Cannot service %s", path); + return delegate.invoke(path, input); + } + + @Override + public Action getDelegate() { + return delegate; + } + } + + ActionServiceAdapter(final BindingToNormalizedNodeCodec codec, final DOMOperationService delegate) { + super(codec, delegate); + } + + @Override + public > T getActionHandle(final Class actionInterface, + final Set> nodes) { + return !nodes.isEmpty() ? (T) new ConstrainedAction(getActionHandle(actionInterface, ImmutableSet.of()), nodes) + : (T) Proxy.newProxyInstance(actionInterface.getClassLoader(), new Class[] { actionInterface }, + getAdapter(actionInterface)); + } + + @Override + ActionAdapter loadAdapter(final Class> key) { + checkArgument(BindingReflections.isBindingClass(key)); + checkArgument(key.isInterface(), "Supplied Action type must be an interface."); + return new ActionAdapter(getCodec(), getDelegate(), key); + } +} diff --git a/binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/BindingAdapterFactory.java b/binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/BindingAdapterFactory.java index 79ac49860b..374758be10 100644 --- a/binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/BindingAdapterFactory.java +++ b/binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/BindingAdapterFactory.java @@ -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.ActionService; import org.opendaylight.mdsal.binding.api.DataBroker; import org.opendaylight.mdsal.binding.api.DataTreeService; import org.opendaylight.mdsal.binding.api.MountPointService; @@ -25,6 +26,7 @@ import org.opendaylight.mdsal.dom.api.DOMDataTreeService; import org.opendaylight.mdsal.dom.api.DOMMountPointService; import org.opendaylight.mdsal.dom.api.DOMNotificationPublishService; import org.opendaylight.mdsal.dom.api.DOMNotificationService; +import org.opendaylight.mdsal.dom.api.DOMOperationService; import org.opendaylight.mdsal.dom.api.DOMRpcProviderService; import org.opendaylight.mdsal.dom.api.DOMRpcService; @@ -126,4 +128,9 @@ public final class BindingAdapterFactory implements AdapterFactory { public RpcProviderService createRpcProviderService(final DOMRpcProviderService domService) { return new BindingDOMRpcProviderServiceAdapter(domService, codec); } + + @Override + public ActionService createActionService(final DOMOperationService domService) { + return new ActionServiceAdapter(codec, domService); + } } diff --git a/binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/RpcResultUtil.java b/binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/RpcResultUtil.java new file mode 100644 index 0000000000..c29e3f0596 --- /dev/null +++ b/binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/RpcResultUtil.java @@ -0,0 +1,37 @@ +/* + * 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 java.util.Collection; +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.opendaylight.mdsal.dom.api.DOMOperationResult; +import org.opendaylight.mdsal.dom.api.DOMRpcResult; +import org.opendaylight.yangtools.yang.common.RpcError; +import org.opendaylight.yangtools.yang.common.RpcError.ErrorSeverity; +import org.opendaylight.yangtools.yang.common.RpcResult; +import org.opendaylight.yangtools.yang.common.RpcResultBuilder; + +/** + * Utility methods for converting {@link RpcResult} to/from {@link DOMOperationResult} and {@link DOMRpcResult}. + */ +@NonNullByDefault +final class RpcResultUtil { + private RpcResultUtil() { + + } + + /** + * DOMRpcResult does not have a notion of success, hence we have to reverse-engineer it by looking at reported + * errors and checking whether they are just warnings. + */ + static RpcResult rpcResultFromDOM(final Collection errors, final @Nullable T result) { + return RpcResultBuilder.status(errors.stream().noneMatch(err -> err.getSeverity() == ErrorSeverity.ERROR)) + .withResult(result).withRpcErrors(errors).build(); + } +} diff --git a/binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/RpcServiceAdapter.java b/binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/RpcServiceAdapter.java index f7ec742788..e835735996 100644 --- a/binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/RpcServiceAdapter.java +++ b/binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/RpcServiceAdapter.java @@ -16,7 +16,6 @@ import com.google.common.util.concurrent.MoreExecutors; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; -import java.util.Collection; import java.util.Map.Entry; import org.opendaylight.mdsal.binding.dom.codec.impl.BindingNormalizedNodeCodecRegistry; import org.opendaylight.mdsal.dom.api.DOMRpcResult; @@ -28,10 +27,7 @@ import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.opendaylight.yangtools.yang.binding.RpcService; import org.opendaylight.yangtools.yang.binding.util.BindingReflections; import org.opendaylight.yangtools.yang.common.QName; -import org.opendaylight.yangtools.yang.common.RpcError; -import org.opendaylight.yangtools.yang.common.RpcError.ErrorSeverity; import org.opendaylight.yangtools.yang.common.RpcResult; -import org.opendaylight.yangtools.yang.common.RpcResultBuilder; import org.opendaylight.yangtools.yang.common.YangConstants; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier; @@ -157,12 +153,7 @@ class RpcServiceAdapter implements InvocationHandler { bindingResult = null; } - // DOMRpcResult does not have a notion of success, hence we have to reverse-engineer it by looking - // at reported errors and checking whether they are just warnings. - final Collection errors = input.getErrors(); - return RpcResult.class.cast(RpcResultBuilder.status(errors.stream() - .noneMatch(error -> error.getSeverity() == ErrorSeverity.ERROR)) - .withResult(bindingResult).withRpcErrors(errors).build()); + return RpcResultUtil.rpcResultFromDOM(input.getErrors(), bindingResult); }, MoreExecutors.directExecutor()); } } diff --git a/binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/osgi/DynamicBindingAdapter.java b/binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/osgi/DynamicBindingAdapter.java index 2991ac1ab3..66e45245ff 100644 --- a/binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/osgi/DynamicBindingAdapter.java +++ b/binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/osgi/DynamicBindingAdapter.java @@ -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.ActionService; import org.opendaylight.mdsal.binding.api.BindingService; import org.opendaylight.mdsal.binding.api.DataBroker; import org.opendaylight.mdsal.binding.api.DataTreeService; @@ -24,6 +25,7 @@ import org.opendaylight.mdsal.dom.api.DOMDataTreeService; import org.opendaylight.mdsal.dom.api.DOMMountPointService; import org.opendaylight.mdsal.dom.api.DOMNotificationPublishService; import org.opendaylight.mdsal.dom.api.DOMNotificationService; +import org.opendaylight.mdsal.dom.api.DOMOperationService; import org.opendaylight.mdsal.dom.api.DOMRpcProviderService; import org.opendaylight.mdsal.dom.api.DOMRpcService; import org.opendaylight.mdsal.dom.api.DOMService; @@ -57,7 +59,8 @@ public final class DynamicBindingAdapter implements AutoCloseable { new AdaptingTracker<>(ctx, DOMRpcService.class, RpcConsumerRegistry.class, factory::createRpcConsumerRegistry), new AdaptingTracker<>(ctx, DOMRpcProviderService.class, RpcProviderService.class, - factory::createRpcProviderService)); + factory::createRpcProviderService), + new AdaptingTracker<>(ctx, DOMOperationService.class, ActionService.class, factory::createActionService)); LOG.debug("Starting {} DOMService trackers", trackers.size()); trackers.forEach(ServiceTracker::open); diff --git a/binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/spi/AdapterFactory.java b/binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/spi/AdapterFactory.java index b96ad26463..8845be6d18 100644 --- a/binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/spi/AdapterFactory.java +++ b/binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/spi/AdapterFactory.java @@ -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.ActionService; import org.opendaylight.mdsal.binding.api.BindingService; import org.opendaylight.mdsal.binding.api.DataBroker; import org.opendaylight.mdsal.binding.api.DataTreeService; @@ -22,6 +23,7 @@ import org.opendaylight.mdsal.dom.api.DOMDataTreeService; import org.opendaylight.mdsal.dom.api.DOMMountPointService; import org.opendaylight.mdsal.dom.api.DOMNotificationPublishService; import org.opendaylight.mdsal.dom.api.DOMNotificationService; +import org.opendaylight.mdsal.dom.api.DOMOperationService; import org.opendaylight.mdsal.dom.api.DOMRpcProviderService; import org.opendaylight.mdsal.dom.api.DOMRpcService; import org.opendaylight.mdsal.dom.api.DOMService; @@ -96,4 +98,13 @@ public interface AdapterFactory { * @throws NullPointerException if {@code domService} is null */ RpcProviderService createRpcProviderService(DOMRpcProviderService domService); + + /** + * Create a {@link ActionService} backed by a {@link DOMOperationService}. + * + * @param domService Backing DOMOperationService + * @return A ActionService + * @throws NullPointerException if {@code domService} is null + */ + ActionService createActionService(DOMOperationService domService); } diff --git a/binding/mdsal-binding-dom-adapter/src/test/java/org/opendaylight/mdsal/binding/dom/adapter/AbstractAdapterTest.java b/binding/mdsal-binding-dom-adapter/src/test/java/org/opendaylight/mdsal/binding/dom/adapter/AbstractAdapterTest.java new file mode 100644 index 0000000000..34f8062855 --- /dev/null +++ b/binding/mdsal-binding-dom-adapter/src/test/java/org/opendaylight/mdsal/binding/dom/adapter/AbstractAdapterTest.java @@ -0,0 +1,26 @@ +/* + * 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 com.google.common.util.concurrent.MoreExecutors; +import org.junit.Before; +import org.opendaylight.mdsal.binding.dom.adapter.test.util.BindingBrokerTestFactory; +import org.opendaylight.mdsal.binding.dom.adapter.test.util.BindingTestContext; + +public abstract class AbstractAdapterTest { + protected BindingToNormalizedNodeCodec codec; + + @Before + public void before() { + final BindingBrokerTestFactory testFactory = new BindingBrokerTestFactory(); + testFactory.setExecutor(MoreExecutors.newDirectExecutorService()); + final BindingTestContext testContext = testFactory.getTestContext(); + testContext.start(); + codec = testContext.getCodec(); + } +} diff --git a/binding/mdsal-binding-dom-adapter/src/test/java/org/opendaylight/mdsal/binding/dom/adapter/ActionServiceAdapterTest.java b/binding/mdsal-binding-dom-adapter/src/test/java/org/opendaylight/mdsal/binding/dom/adapter/ActionServiceAdapterTest.java new file mode 100644 index 0000000000..ffe84cfc88 --- /dev/null +++ b/binding/mdsal-binding-dom-adapter/src/test/java/org/opendaylight/mdsal/binding/dom/adapter/ActionServiceAdapterTest.java @@ -0,0 +1,91 @@ +/* + * 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 org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.doReturn; +import static org.opendaylight.yangtools.yang.common.YangConstants.operationInputQName; +import static org.opendaylight.yangtools.yang.common.YangConstants.operationOutputQName; +import static org.opendaylight.yangtools.yang.data.impl.schema.Builders.containerBuilder; +import static org.opendaylight.yangtools.yang.data.impl.schema.Builders.leafBuilder; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; +import com.google.common.util.concurrent.FluentFuture; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.SettableFuture; +import java.util.concurrent.ExecutionException; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.opendaylight.mdsal.binding.api.ActionService; +import org.opendaylight.mdsal.dom.api.DOMOperationResult; +import org.opendaylight.mdsal.dom.api.DOMOperationService; +import org.opendaylight.mdsal.dom.spi.SimpleDOMOperationResult; +import org.opendaylight.yang.gen.v1.urn.odl.actions.norev.Cont; +import org.opendaylight.yang.gen.v1.urn.odl.actions.norev.cont.Foo; +import org.opendaylight.yang.gen.v1.urn.odl.actions.norev.cont.foo.Input; +import org.opendaylight.yang.gen.v1.urn.odl.actions.norev.cont.foo.InputBuilder; +import org.opendaylight.yang.gen.v1.urn.odl.actions.norev.cont.foo.Output; +import org.opendaylight.yang.gen.v1.urn.odl.actions.norev.cont.foo.OutputBuilder; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.binding.RpcOutput; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.common.RpcResult; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier; +import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode; + +public class ActionServiceAdapterTest extends AbstractAdapterTest { + private static final NodeIdentifier FOO_INPUT = NodeIdentifier.create(operationInputQName(Foo.QNAME.getModule())); + private static final NodeIdentifier FOO_OUTPUT = NodeIdentifier.create(operationOutputQName(Foo.QNAME.getModule())); + private static final NodeIdentifier FOO_XYZZY = NodeIdentifier.create(QName.create(Foo.QNAME, "xyzzy")); + private static final ContainerNode DOM_FOO_INPUT = containerBuilder().withNodeIdentifier(FOO_INPUT) + .withChild(leafBuilder().withNodeIdentifier(FOO_XYZZY).withValue("xyzzy").build()) + .build(); + private static final ContainerNode DOM_FOO_OUTPUT = containerBuilder().withNodeIdentifier(FOO_OUTPUT).build(); + private static final Input BINDING_FOO_INPUT = new InputBuilder().setXyzzy("xyzzy").build(); + private static final RpcOutput BINDING_FOO_OUTPUT = new OutputBuilder().build(); + + @Mock + private DOMOperationService delegate; + + private ActionService service; + + private SettableFuture domResult; + + @Override + @Before + public void before() { + MockitoAnnotations.initMocks(this); + super.before(); + + domResult = SettableFuture.create(); + doReturn(domResult).when(delegate).invokeAction(any(), any(), any()); + + service = new ActionServiceAdapter(codec, delegate); + } + + @Test + public void testInvocation() throws ExecutionException { + final Foo handle = service.getActionHandle(Foo.class, ImmutableSet.of()); + final FluentFuture> future = handle.invoke(InstanceIdentifier.create(Cont.class), + BINDING_FOO_INPUT); + assertNotNull(future); + assertFalse(future.isDone()); + domResult.set(new SimpleDOMOperationResult(DOM_FOO_OUTPUT, ImmutableList.of())); + final RpcResult bindingResult = Futures.getDone(future); + + assertEquals(ImmutableList.of(), bindingResult.getErrors()); + assertEquals(BINDING_FOO_OUTPUT, bindingResult.getResult()); + } + +} diff --git a/binding/mdsal-binding-dom-adapter/src/test/java/org/opendaylight/mdsal/binding/dom/adapter/BindingDOMDataTreeServiceAdapterTest.java b/binding/mdsal-binding-dom-adapter/src/test/java/org/opendaylight/mdsal/binding/dom/adapter/BindingDOMDataTreeServiceAdapterTest.java index 152f484f3b..c136460416 100644 --- a/binding/mdsal-binding-dom-adapter/src/test/java/org/opendaylight/mdsal/binding/dom/adapter/BindingDOMDataTreeServiceAdapterTest.java +++ b/binding/mdsal-binding-dom-adapter/src/test/java/org/opendaylight/mdsal/binding/dom/adapter/BindingDOMDataTreeServiceAdapterTest.java @@ -15,44 +15,39 @@ import static org.mockito.Mockito.verify; import static org.mockito.MockitoAnnotations.initMocks; import com.google.common.collect.ImmutableSet; -import com.google.common.util.concurrent.MoreExecutors; import org.junit.Before; import org.junit.Test; import org.mockito.Mock; import org.opendaylight.mdsal.binding.api.DataTreeListener; -import org.opendaylight.mdsal.binding.dom.adapter.test.util.BindingBrokerTestFactory; -import org.opendaylight.mdsal.binding.dom.adapter.test.util.BindingTestContext; +import org.opendaylight.mdsal.binding.api.DataTreeLoopException; import org.opendaylight.mdsal.dom.api.DOMDataTreeProducer; import org.opendaylight.mdsal.dom.api.DOMDataTreeService; -public class BindingDOMDataTreeServiceAdapterTest { +public class BindingDOMDataTreeServiceAdapterTest extends AbstractAdapterTest { private BindingDOMDataTreeServiceAdapter bindingDOMDataTreeServiceAdapter; - private BindingToNormalizedNodeCodec codec; @Mock private DOMDataTreeService delegate; + @Override @Before - public void setUp() throws Exception { + public void before() { initMocks(this); - final BindingBrokerTestFactory testFactory = new BindingBrokerTestFactory(); - testFactory.setExecutor(MoreExecutors.newDirectExecutorService()); - final BindingTestContext testContext = testFactory.getTestContext(); - testContext.start(); - codec = testContext.getCodec(); + super.before(); + bindingDOMDataTreeServiceAdapter = BindingDOMDataTreeServiceAdapter.create(delegate, codec); } @Test - public void createProducerTest() throws Exception { + public void createProducerTest() { doReturn(mock(DOMDataTreeProducer.class)).when(delegate).createProducer(any()); assertNotNull(bindingDOMDataTreeServiceAdapter.createProducer(ImmutableSet.of())); verify(delegate).createProducer(any()); } @Test(expected = UnsupportedOperationException.class) - public void registerListenerTest() throws Exception { + public void registerListenerTest() throws DataTreeLoopException { bindingDOMDataTreeServiceAdapter.registerListener(mock(DataTreeListener.class), ImmutableSet.of(), false, ImmutableSet.of()); } diff --git a/dom/mdsal-dom-spi/src/main/java/org/opendaylight/mdsal/dom/spi/SimpleDOMOperationResult.java b/dom/mdsal-dom-spi/src/main/java/org/opendaylight/mdsal/dom/spi/SimpleDOMOperationResult.java index 67b449fe36..0ec10c47b8 100644 --- a/dom/mdsal-dom-spi/src/main/java/org/opendaylight/mdsal/dom/spi/SimpleDOMOperationResult.java +++ b/dom/mdsal-dom-spi/src/main/java/org/opendaylight/mdsal/dom/spi/SimpleDOMOperationResult.java @@ -32,7 +32,7 @@ public final class SimpleDOMOperationResult implements DOMOperationResult, Immut private SimpleDOMOperationResult(final Collection errors, final @Nullable ContainerNode output) { this.errors = ImmutableList.copyOf(errors); - this.output = null; + this.output = output; } public SimpleDOMOperationResult(final Collection errors) {