Add ActionServiceAdapter to adapt DOMActionService.
Change-Id: I303ab2007561f2b348d4e691fa04d9b49f0eaf1c
Signed-off-by: Jie Han <han.jie@zte.com.cn>
--- /dev/null
+/*
+ * 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<? extends Action<? extends TreeNode, ?, ?, ?>> type;
+ private final BindingToNormalizedNodeCodec codec;
+ private final DOMActionService delegate;
+ private final Action<? extends TreeNode, ?, ?, ?> proxy;
+ private final SchemaPath path;
+
+ ActionServiceAdapter(final Class<? extends Action<? extends TreeNode, ?, ?, ?>> 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<? extends TreeNode, ?, ?, ?>) Proxy.newProxyInstance(type.getClassLoader(),
+ new Class[] { type }, this);
+ }
+
+ public BindingToNormalizedNodeCodec getCodec() {
+ return codec;
+ }
+
+ public DOMActionService getDelegate() {
+ return delegate;
+ }
+
+ Action<? extends TreeNode, ?, ?, ?> getProxy() {
+ return proxy;
+ }
+
+ public Class<? extends Action<? extends TreeNode, ?, ?, ?>> 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<Output> callback = (RpcCallback<Output>) requireNonNull(args[2]);
+
+ final FluentFuture<? extends DOMActionResult> 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<RpcResult<?>> bindingFuture =
+ ((LazyDOMActionResultFuture) future).getBindingFuture();
+ Futures.addCallback(bindingFuture, new FutureCallback<RpcResult<?>>() {
+
+ @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<RpcError> 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<DOMActionResult>() {
+
+ @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.");
+ }
+}
*/
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;
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.
*/
AbstractImplAdapter(final BindingNormalizedNodeCodecRegistry codec, final Class<? extends Operation> 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();
}
*/
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;
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.
*/
public static final Factory<RpcActionConsumerRegistry> BUILDER_FACTORY = Builder::new;
- private final DOMRpcService domService;
+ private final DOMRpcService domRpcService;
+ private final DOMActionService domActionService;
private final BindingToNormalizedNodeCodec codec;
- private final LoadingCache<Class<? extends Operation>, RpcServiceAdapter> proxies = CacheBuilder.newBuilder()
- .weakKeys().build(new CacheLoader<Class<? extends Operation>, RpcServiceAdapter>() {
+ private final LoadingCache<Class<? extends Rpc<?, ?>>, RpcServiceAdapter> rpcProxies = CacheBuilder.newBuilder()
+ .weakKeys().build(new CacheLoader<Class<? extends Rpc<?, ?>>, RpcServiceAdapter>() {
@SuppressWarnings("unchecked")
- private RpcServiceAdapter createProxy(final Class<? extends Operation> key) {
+ private RpcServiceAdapter createProxy(final Class<? extends Rpc<?, ?>> 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<? extends Rpc<?, ?>>) 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<? extends Operation> key) throws Exception {
+ public RpcServiceAdapter load(@Nonnull final Class<? extends Rpc<?, ?>> 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<Class<? extends Action<? extends TreeNode, ?, ?, ?>>, ActionServiceAdapter>
+ actionProxies = CacheBuilder.newBuilder().weakKeys().build(
+ new CacheLoader<Class<? extends Action<? extends TreeNode, ?, ?, ?>>, ActionServiceAdapter>() {
+
+ @SuppressWarnings("unchecked")
+ private ActionServiceAdapter createProxy(
+ final Class<? extends Action<? extends TreeNode, ?, ?, ?>> 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<? extends Action<? extends TreeNode, ?, ?, ?>> 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 extends Rpc<?, ?>> T getRpcService(final Class<T> 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<RpcActionConsumerRegistry> {
@Override
protected RpcActionConsumerRegistry createInstance(final BindingToNormalizedNodeCodec codec,
final ClassToInstanceMap<DOMService> 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<? extends Class<? extends DOMService>> getRequiredDelegates() {
- return ImmutableSet.of(DOMRpcService.class);
+ return ImmutableSet.of(DOMRpcService.class, DOMActionService.class);
}
}
+ @SuppressWarnings("unchecked")
@Override
public <T extends Action<? extends TreeNode, ?, ?, ?>> T getActionService(final Class<T> 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 extends ListAction<? extends TreeNode, ?, ?, ?>> T getListActionService(final Class<T> serviceInterface) {
- // TODO implement after improve DOM part of MD-SAL for support of Yang 1.1
- throw new UnsupportedOperationException();
+ return getActionService(serviceInterface);
}
}
*/
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;
private LazyDOMActionResultFuture(final ListenableFuture<RpcResult<?>> 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<DOMActionResult> create(final BindingNormalizedNodeCodecRegistry codec,
*/
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;
private LazyDOMRpcResultFuture(final ListenableFuture<RpcResult<?>> 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<DOMRpcResult> create(final BindingNormalizedNodeCodecRegistry codec,
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;
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);
return domRouter.getRpcService();
}
+ public DOMActionService getDomActionService() {
+ return domRouter.getActionService();
+ }
+
@Override
public void close() throws Exception {