From: Robert Varga Date: Mon, 16 Jul 2018 12:41:01 +0000 (+0200) Subject: Add ActionProviderService adapter X-Git-Tag: release/fluorine~24 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=commitdiff_plain;h=b4f58d7fb693ae61cefc69a991f8b5a1af71ab83;p=mdsal.git Add ActionProviderService adapter A mostly straightforward implementation of ActionProviderService on top of a DOMOperationProviderService. Change-Id: I50b7f2d7b03059088be9ba277999c11bc085b385 Signed-off-by: Robert Varga --- 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 index 0000000000..11bc55dc1a --- /dev/null +++ b/binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/ActionProviderServiceAdapter.java @@ -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 + implements ActionProviderService { + ActionProviderServiceAdapter(final BindingToNormalizedNodeCodec codec, final DOMActionProviderService delegate) { + super(codec, delegate); + } + + @Override + public , + T extends org.opendaylight.yangtools.yang.binding.Action, S extends T> + ObjectRegistration registerImplementation(final Class actionInterface, final S implementation, + final LogicalDatastoreType datastore, final Set> validNodes) { + final SchemaPath path = getCodec().getActionPath(actionInterface); + final ObjectRegistration reg = getDelegate().registerActionImplementation( + new Impl(getCodec(), + NodeIdentifier.create(YangConstants.operationOutputQName(path.getLastComponent().getModule())), + actionInterface, implementation), ImmutableSet.of()); + return new AbstractObjectRegistration(implementation) { + @Override + protected void removeRegistration() { + reg.close(); + } + }; + } + + private static final class Impl implements DOMActionImplementation { + private final Class> actionInterface; + private final Action implementation; + private final BindingNormalizedNodeSerializer codec; + private final NodeIdentifier outputName; + + Impl(final BindingNormalizedNodeSerializer codec, final NodeIdentifier outputName, + final Class> 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 invokeAction(final SchemaPath type, + final DOMDataTreeIdentifier path, final ContainerNode input) { + final FluentFuture> 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); + } + } +} 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 bd8cc14382..6af1f88691 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.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 index 0000000000..80bbd7e5f9 --- /dev/null +++ b/binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/BindingOperationFluentFuture.java @@ -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 extends AbstractFuture + implements BindingRpcFutureAware { + private final ListenableFuture> userFuture; + private final Class> action; + private final NodeIdentifier identifier; + + private BindingNormalizedNodeSerializer codec; + + BindingOperationFluentFuture(final FluentFuture> userFuture, + final Class> 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> getBindingFuture() { + return (ListenableFuture) userFuture; + } + + @SuppressWarnings("checkstyle:illegalCatch") + private void userFutureCompleted() { + final DOMActionResult domResult; + + try { + final RpcResult 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); + } +} 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 825fda6fdf..939f70c5d7 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.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); 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 22f7731cdb..f6229f3d04 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.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); }