From: Jie Han Date: Wed, 15 Aug 2018 06:20:58 +0000 (+0800) Subject: Binding2 - Add ActionServiceAdapter X-Git-Tag: v3.0.0~52 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=commitdiff_plain;h=e5df86aa4574580658bf285d414d378e2c743129;p=mdsal.git Binding2 - Add ActionServiceAdapter Add ActionServiceAdapter to adapt DOMActionService. Change-Id: I303ab2007561f2b348d4e691fa04d9b49f0eaf1c Signed-off-by: Jie Han --- diff --git a/binding2/mdsal-binding2-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/adapter/impl/operation/ActionServiceAdapter.java b/binding2/mdsal-binding2-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/adapter/impl/operation/ActionServiceAdapter.java new file mode 100644 index 0000000000..7b82d4a73b --- /dev/null +++ b/binding2/mdsal-binding2-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/adapter/impl/operation/ActionServiceAdapter.java @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2017 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.javav2.dom.adapter.impl.operation; + +import static java.util.Objects.requireNonNull; + +import com.google.common.annotations.Beta; +import com.google.common.util.concurrent.FluentFuture; +import com.google.common.util.concurrent.FutureCallback; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.MoreExecutors; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.BindingToNormalizedNodeCodec; +import org.opendaylight.mdsal.binding.javav2.dom.codec.serialized.LazySerializedContainerNode; +import org.opendaylight.mdsal.binding.javav2.spec.base.Action; +import org.opendaylight.mdsal.binding.javav2.spec.base.Input; +import org.opendaylight.mdsal.binding.javav2.spec.base.InstanceIdentifier; +import org.opendaylight.mdsal.binding.javav2.spec.base.Output; +import org.opendaylight.mdsal.binding.javav2.spec.base.RpcCallback; +import org.opendaylight.mdsal.binding.javav2.spec.base.TreeNode; +import org.opendaylight.mdsal.common.api.LogicalDatastoreType; +import org.opendaylight.mdsal.dom.api.DOMActionResult; +import org.opendaylight.mdsal.dom.api.DOMActionService; +import org.opendaylight.mdsal.dom.api.DOMDataTreeIdentifier; +import org.opendaylight.yangtools.yang.common.RpcResult; +import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode; +import org.opendaylight.yangtools.yang.model.api.SchemaPath; + +@Beta +class ActionServiceAdapter implements InvocationHandler { + + private final Class> type; + private final BindingToNormalizedNodeCodec codec; + private final DOMActionService delegate; + private final Action proxy; + private final SchemaPath path; + + ActionServiceAdapter(final Class> type, + final BindingToNormalizedNodeCodec codec, final DOMActionService domService) { + this.type = requireNonNull(type); + this.codec = requireNonNull(codec); + this.delegate = requireNonNull(domService); + this.path = getCodec().getActionPath(type); + proxy = (Action) Proxy.newProxyInstance(type.getClassLoader(), + new Class[] { type }, this); + } + + public BindingToNormalizedNodeCodec getCodec() { + return codec; + } + + public DOMActionService getDelegate() { + return delegate; + } + + Action getProxy() { + return proxy; + } + + public Class> getType() { + return type; + } + + public SchemaPath getPath() { + return path; + } + + @Override + @SuppressWarnings("checkstyle:hiddenField") + public Object invoke(final Object proxy, final Method method, final Object[] args) { + + 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 Input input = (Input) requireNonNull(args[0]); + final InstanceIdentifier path = (InstanceIdentifier) requireNonNull(args[1]); + final RpcCallback callback = (RpcCallback) requireNonNull(args[2]); + + final FluentFuture future = getDelegate().invokeAction(getPath(), + new DOMDataTreeIdentifier(LogicalDatastoreType.OPERATIONAL, getCodec().toNormalized(path)), + (ContainerNode) LazySerializedContainerNode.create(getPath(), (TreeNode) input, + getCodec().getCodecRegistry())); + //FIXME:this part is ugly, how to bridge FluentFuture and RpcCallback better? + // Invocation returned a future we know about -- return that future instead + if (future instanceof LazyDOMActionResultFuture) { + ListenableFuture> bindingFuture = + ((LazyDOMActionResultFuture) future).getBindingFuture(); + Futures.addCallback(bindingFuture, new FutureCallback>() { + + @Override + public void onSuccess(final RpcResult result) { + if (result.isSuccessful()) { + callback.onSuccess((Output) result.getResult()); + } else { + //FIXME: It's not suitable to do this way here. It's better for + // 'onFailure' to accept Collection as input. + result.getErrors().forEach(e -> callback.onFailure(e.getCause())); + } + } + + @Override + public void onFailure(final Throwable throwable) { + callback.onFailure(throwable); + } + }, MoreExecutors.directExecutor()); + } else { + Futures.addCallback(future, new FutureCallback() { + + @Override + public void onSuccess(final DOMActionResult result) { + if (result.getErrors().isEmpty()) { + callback.onSuccess((Output) getCodec().fromNormalizedNodeOperationData(getPath(), + result.getOutput().get())); + } else { + result.getErrors().forEach(e -> callback.onFailure(e.getCause())); + } + } + + @Override + public void onFailure(final Throwable throwable) { + callback.onFailure(throwable); + } + }, MoreExecutors.directExecutor()); + } + } + break; + default: + break; + } + + throw new UnsupportedOperationException("Method " + method.toString() + "is unsupported."); + } +} diff --git a/binding2/mdsal-binding2-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/adapter/impl/operation/BindingDOMOperationProviderServiceAdapter.java b/binding2/mdsal-binding2-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/adapter/impl/operation/BindingDOMOperationProviderServiceAdapter.java index dd70882149..4b2f2f0e96 100644 --- a/binding2/mdsal-binding2-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/adapter/impl/operation/BindingDOMOperationProviderServiceAdapter.java +++ b/binding2/mdsal-binding2-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/adapter/impl/operation/BindingDOMOperationProviderServiceAdapter.java @@ -7,8 +7,9 @@ */ package org.opendaylight.mdsal.binding.javav2.dom.adapter.impl.operation; +import static java.util.Objects.requireNonNull; + import com.google.common.annotations.Beta; -import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableSet; import com.google.common.util.concurrent.FluentFuture; import com.google.common.util.concurrent.SettableFuture; @@ -57,7 +58,6 @@ import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode; import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; import org.opendaylight.yangtools.yang.model.api.SchemaPath; -//FIXME missing support of Action operation (dependence on support of Yang 1.1 in DOM part of MD-SAL) /** * Operation service provider adapter. */ @@ -132,8 +132,8 @@ public class BindingDOMOperationProviderServiceAdapter implements RpcActionProvi AbstractImplAdapter(final BindingNormalizedNodeCodecRegistry codec, final Class clazz, final D delegate) { - this.codec = Preconditions.checkNotNull(codec); - this.delegate = Preconditions.checkNotNull(delegate); + this.codec = requireNonNull(codec); + this.delegate = requireNonNull(delegate); inputQname = QName.create(BindingReflections.getQNameModule(clazz), "input").intern(); } diff --git a/binding2/mdsal-binding2-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/adapter/impl/operation/BindingDOMOperationServiceAdapter.java b/binding2/mdsal-binding2-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/adapter/impl/operation/BindingDOMOperationServiceAdapter.java index 251f4fefcd..5a37937e95 100644 --- a/binding2/mdsal-binding2-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/adapter/impl/operation/BindingDOMOperationServiceAdapter.java +++ b/binding2/mdsal-binding2-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/adapter/impl/operation/BindingDOMOperationServiceAdapter.java @@ -7,6 +7,8 @@ */ package org.opendaylight.mdsal.binding.javav2.dom.adapter.impl.operation; +import static java.util.Objects.requireNonNull; + import com.google.common.annotations.Beta; import com.google.common.base.Preconditions; import com.google.common.cache.CacheBuilder; @@ -23,13 +25,12 @@ import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.BindingToNormalizedN import org.opendaylight.mdsal.binding.javav2.runtime.reflection.BindingReflections; import org.opendaylight.mdsal.binding.javav2.spec.base.Action; import org.opendaylight.mdsal.binding.javav2.spec.base.ListAction; -import org.opendaylight.mdsal.binding.javav2.spec.base.Operation; import org.opendaylight.mdsal.binding.javav2.spec.base.Rpc; import org.opendaylight.mdsal.binding.javav2.spec.base.TreeNode; +import org.opendaylight.mdsal.dom.api.DOMActionService; import org.opendaylight.mdsal.dom.api.DOMRpcService; import org.opendaylight.mdsal.dom.api.DOMService; -//FIXME implement after improve DOM part of MD-SAL for support of Yang 1.1 /** * Adapter for operation service. */ @@ -38,41 +39,68 @@ public class BindingDOMOperationServiceAdapter implements RpcActionConsumerRegis public static final Factory BUILDER_FACTORY = Builder::new; - private final DOMRpcService domService; + private final DOMRpcService domRpcService; + private final DOMActionService domActionService; private final BindingToNormalizedNodeCodec codec; - private final LoadingCache, RpcServiceAdapter> proxies = CacheBuilder.newBuilder() - .weakKeys().build(new CacheLoader, RpcServiceAdapter>() { + private final LoadingCache>, RpcServiceAdapter> rpcProxies = CacheBuilder.newBuilder() + .weakKeys().build(new CacheLoader>, RpcServiceAdapter>() { @SuppressWarnings("unchecked") - private RpcServiceAdapter createProxy(final Class key) { + private RpcServiceAdapter createProxy(final Class> key) { Preconditions.checkArgument(BindingReflections.isBindingClass(key)); Preconditions.checkArgument(key.isInterface(), "Supplied Operation service type must be interface."); if (Rpc.class.isAssignableFrom(key)) { - return new RpcServiceAdapter((Class>) key, codec, domService); + return new RpcServiceAdapter(key, codec, domRpcService); } - // TODO implement after improve DOM part of MD-SAL for support of Yang 1.1 + throw new UnsupportedOperationException(); } @Nonnull @Override - public RpcServiceAdapter load(@Nonnull final Class key) throws Exception { + public RpcServiceAdapter load(@Nonnull final Class> key) { return createProxy(key); } }); - public BindingDOMOperationServiceAdapter(final DOMRpcService domService, final BindingToNormalizedNodeCodec codec) { - this.domService = Preconditions.checkNotNull(domService); - this.codec = Preconditions.checkNotNull(codec); + private final LoadingCache>, ActionServiceAdapter> + actionProxies = CacheBuilder.newBuilder().weakKeys().build( + new CacheLoader>, ActionServiceAdapter>() { + + @SuppressWarnings("unchecked") + private ActionServiceAdapter createProxy( + final Class> key) { + Preconditions.checkArgument(BindingReflections.isBindingClass(key)); + Preconditions.checkArgument(key.isInterface(), + "Supplied Operation service type must be interface."); + if (Action.class.isAssignableFrom(key)) { + return new ActionServiceAdapter(key, codec, domActionService); + } + + throw new UnsupportedOperationException(); + } + + @Nonnull + @Override + public ActionServiceAdapter load(@Nonnull + final Class> key) { + return createProxy(key); + } + }); + + public BindingDOMOperationServiceAdapter(final DOMRpcService domRpcService, final DOMActionService domActionService, + final BindingToNormalizedNodeCodec codec) { + this.domRpcService = requireNonNull(domRpcService); + this.domActionService = requireNonNull(domActionService); + this.codec = requireNonNull(codec); } @SuppressWarnings("unchecked") @Override public > T getRpcService(final Class rpc) { - Preconditions.checkArgument(rpc != null, "Rpc needs to be specified."); - return (T) proxies.getUnchecked(rpc).getProxy(); + return (T) rpcProxies.getUnchecked(requireNonNull(rpc)).getProxy(); } private static final class Builder extends BindingDOMAdapterBuilder { @@ -80,25 +108,25 @@ public class BindingDOMOperationServiceAdapter implements RpcActionConsumerRegis @Override protected RpcActionConsumerRegistry createInstance(final BindingToNormalizedNodeCodec codec, final ClassToInstanceMap delegates) { - final DOMRpcService domRpc = delegates.getInstance(DOMRpcService.class); - return new BindingDOMOperationServiceAdapter(domRpc, codec); + final DOMRpcService domRpcService = delegates.getInstance(DOMRpcService.class); + final DOMActionService domActionService = delegates.getInstance(DOMActionService.class); + return new BindingDOMOperationServiceAdapter(domRpcService, domActionService, codec); } @Override public Set> getRequiredDelegates() { - return ImmutableSet.of(DOMRpcService.class); + return ImmutableSet.of(DOMRpcService.class, DOMActionService.class); } } + @SuppressWarnings("unchecked") @Override public > T getActionService(final Class serviceInterface) { - // TODO implement after improve DOM part of MD-SAL for support of Yang 1.1 - throw new UnsupportedOperationException(); + return (T) actionProxies.getUnchecked(requireNonNull(serviceInterface)).getProxy(); } @Override public > T getListActionService(final Class serviceInterface) { - // TODO implement after improve DOM part of MD-SAL for support of Yang 1.1 - throw new UnsupportedOperationException(); + return getActionService(serviceInterface); } } diff --git a/binding2/mdsal-binding2-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/adapter/impl/operation/LazyDOMActionResultFuture.java b/binding2/mdsal-binding2-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/adapter/impl/operation/LazyDOMActionResultFuture.java index 54c1748379..24c880ec5f 100644 --- a/binding2/mdsal-binding2-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/adapter/impl/operation/LazyDOMActionResultFuture.java +++ b/binding2/mdsal-binding2-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/adapter/impl/operation/LazyDOMActionResultFuture.java @@ -7,8 +7,9 @@ */ package org.opendaylight.mdsal.binding.javav2.dom.adapter.impl.operation; +import static java.util.Objects.requireNonNull; + import com.google.common.annotations.Beta; -import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.google.common.util.concurrent.AbstractFuture; import com.google.common.util.concurrent.FluentFuture; @@ -48,8 +49,8 @@ final class LazyDOMActionResultFuture extends AbstractFuture { private LazyDOMActionResultFuture(final ListenableFuture> delegate, final BindingNormalizedNodeCodecRegistry codec) { - this.bindingFuture = Preconditions.checkNotNull(delegate, "delegate"); - this.codec = Preconditions.checkNotNull(codec, "codec"); + this.bindingFuture = requireNonNull(delegate, "delegate"); + this.codec = requireNonNull(codec, "codec"); } static FluentFuture create(final BindingNormalizedNodeCodecRegistry codec, diff --git a/binding2/mdsal-binding2-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/adapter/impl/operation/LazyDOMRpcResultFuture.java b/binding2/mdsal-binding2-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/adapter/impl/operation/LazyDOMRpcResultFuture.java index 0df3547845..a37279c24f 100644 --- a/binding2/mdsal-binding2-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/adapter/impl/operation/LazyDOMRpcResultFuture.java +++ b/binding2/mdsal-binding2-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/adapter/impl/operation/LazyDOMRpcResultFuture.java @@ -7,8 +7,9 @@ */ package org.opendaylight.mdsal.binding.javav2.dom.adapter.impl.operation; +import static java.util.Objects.requireNonNull; + import com.google.common.annotations.Beta; -import com.google.common.base.Preconditions; import com.google.common.util.concurrent.AbstractFuture; import com.google.common.util.concurrent.FluentFuture; import com.google.common.util.concurrent.ListenableFuture; @@ -48,8 +49,8 @@ final class LazyDOMRpcResultFuture extends AbstractFuture { private LazyDOMRpcResultFuture(final ListenableFuture> delegate, final BindingNormalizedNodeCodecRegistry codec) { - this.bindingFuture = Preconditions.checkNotNull(delegate, "delegate"); - this.codec = Preconditions.checkNotNull(codec, "codec"); + this.bindingFuture = requireNonNull(delegate, "delegate"); + this.codec = requireNonNull(codec, "codec"); } static FluentFuture create(final BindingNormalizedNodeCodecRegistry codec, diff --git a/binding2/mdsal-binding2-dom-adapter/src/test/java/org/opendaylight/mdsal/binding/javav2/dom/adapter/test/BindingTestContext.java b/binding2/mdsal-binding2-dom-adapter/src/test/java/org/opendaylight/mdsal/binding/javav2/dom/adapter/test/BindingTestContext.java index 1e42a9a1d5..5c69781ce0 100644 --- a/binding2/mdsal-binding2-dom-adapter/src/test/java/org/opendaylight/mdsal/binding/javav2/dom/adapter/test/BindingTestContext.java +++ b/binding2/mdsal-binding2-dom-adapter/src/test/java/org/opendaylight/mdsal/binding/javav2/dom/adapter/test/BindingTestContext.java @@ -37,6 +37,7 @@ import org.opendaylight.mdsal.binding.javav2.runtime.reflection.BindingReflectio import org.opendaylight.mdsal.binding.javav2.spec.runtime.YangModuleInfo; import org.opendaylight.mdsal.common.api.LogicalDatastoreType; 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.DOMMountPointService; import org.opendaylight.mdsal.dom.api.DOMNotificationPublishService; @@ -119,7 +120,7 @@ public class BindingTestContext implements AutoCloseable { public void startBindingBroker() { checkState(executor != null, "Executor needs to be set"); - baConsumerRpc = new BindingDOMOperationServiceAdapter(getDomRpcInvoker(), codec); + baConsumerRpc = new BindingDOMOperationServiceAdapter(getDomRpcInvoker(), getDomActionService(), codec); baProviderRpc = new BindingDOMOperationProviderServiceAdapter(getDomRpcRegistry(), getDomActionRegistry(), codec); final MountPointService mountService = new BindingDOMMountPointServiceAdapter(biMountImpl, codec); @@ -208,6 +209,10 @@ public class BindingTestContext implements AutoCloseable { return domRouter.getRpcService(); } + public DOMActionService getDomActionService() { + return domRouter.getActionService(); + } + @Override public void close() throws Exception {