2 * Copyright (c) 2017 Pantheon Technologies s.r.o. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.mdsal.binding.javav2.dom.adapter.impl.operation;
10 import static java.util.Objects.requireNonNull;
12 import com.google.common.annotations.Beta;
13 import com.google.common.collect.ImmutableSet;
14 import com.google.common.util.concurrent.FluentFuture;
15 import com.google.common.util.concurrent.SettableFuture;
16 import java.util.ArrayList;
17 import java.util.Collection;
18 import java.util.HashSet;
20 import java.util.concurrent.CompletableFuture;
21 import javax.annotation.Nonnull;
22 import javax.annotation.Nullable;
23 import org.opendaylight.mdsal.binding.javav2.api.DataTreeIdentifier;
24 import org.opendaylight.mdsal.binding.javav2.api.RpcActionProviderService;
25 import org.opendaylight.mdsal.binding.javav2.dom.adapter.impl.operation.BindingDOMOperationProviderServiceAdapter.AbstractImplAdapter.ActionAdapter;
26 import org.opendaylight.mdsal.binding.javav2.dom.adapter.impl.operation.BindingDOMOperationProviderServiceAdapter.AbstractImplAdapter.RpcAdapter;
27 import org.opendaylight.mdsal.binding.javav2.dom.adapter.registration.BindingDOMOperationAdapterRegistration;
28 import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.BindingNormalizedNodeCodecRegistry;
29 import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.BindingToNormalizedNodeCodec;
30 import org.opendaylight.mdsal.binding.javav2.dom.codec.serialized.LazySerializedContainerNode;
31 import org.opendaylight.mdsal.binding.javav2.runtime.reflection.BindingReflections;
32 import org.opendaylight.mdsal.binding.javav2.spec.base.Action;
33 import org.opendaylight.mdsal.binding.javav2.spec.base.Input;
34 import org.opendaylight.mdsal.binding.javav2.spec.base.InstanceIdentifier;
35 import org.opendaylight.mdsal.binding.javav2.spec.base.Operation;
36 import org.opendaylight.mdsal.binding.javav2.spec.base.Output;
37 import org.opendaylight.mdsal.binding.javav2.spec.base.Rpc;
38 import org.opendaylight.mdsal.binding.javav2.spec.base.RpcCallback;
39 import org.opendaylight.mdsal.binding.javav2.spec.base.TreeNode;
40 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
41 import org.opendaylight.mdsal.dom.api.DOMActionImplementation;
42 import org.opendaylight.mdsal.dom.api.DOMActionInstance;
43 import org.opendaylight.mdsal.dom.api.DOMActionProviderService;
44 import org.opendaylight.mdsal.dom.api.DOMActionResult;
45 import org.opendaylight.mdsal.dom.api.DOMDataTreeIdentifier;
46 import org.opendaylight.mdsal.dom.api.DOMRpcIdentifier;
47 import org.opendaylight.mdsal.dom.api.DOMRpcImplementation;
48 import org.opendaylight.mdsal.dom.api.DOMRpcImplementationRegistration;
49 import org.opendaylight.mdsal.dom.api.DOMRpcProviderService;
50 import org.opendaylight.mdsal.dom.api.DOMRpcResult;
51 import org.opendaylight.yangtools.concepts.ObjectRegistration;
52 import org.opendaylight.yangtools.yang.common.QName;
53 import org.opendaylight.yangtools.yang.common.RpcError.ErrorType;
54 import org.opendaylight.yangtools.yang.common.RpcResult;
55 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
56 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
57 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
58 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
59 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
62 * Operation service provider adapter.
65 public class BindingDOMOperationProviderServiceAdapter implements RpcActionProviderService {
67 private static final Set<YangInstanceIdentifier> GLOBAL = ImmutableSet.of(YangInstanceIdentifier.builder().build());
68 private final BindingToNormalizedNodeCodec codec;
69 private final DOMRpcProviderService domRpcRegistry;
70 private final DOMActionProviderService domActionRegistry;
72 public BindingDOMOperationProviderServiceAdapter(final DOMRpcProviderService domRpcRegistry,
73 final DOMActionProviderService domActionRegistry, final BindingToNormalizedNodeCodec codec) {
75 this.domRpcRegistry = domRpcRegistry;
76 this.domActionRegistry = domActionRegistry;
80 public <S extends Rpc<?, ?>, T extends S> ObjectRegistration<T> registerRpcImplementation(final Class<S> type,
81 final T implementation) {
82 return register(type, implementation, GLOBAL);
86 public <S extends Rpc<?, ?>, T extends S> ObjectRegistration<T> registerRpcImplementation(final Class<S> type,
87 final T implementation, final Set<InstanceIdentifier<?>> paths) {
88 return register(type, implementation, toYangInstanceIdentifiers(paths));
91 private <S extends Rpc<?, ?>, T extends S> ObjectRegistration<T> register(final Class<S> type,
92 final T implementation, final Collection<YangInstanceIdentifier> rpcContextPaths) {
93 final SchemaPath path = codec.getRpcPath(type);
94 final Set<DOMRpcIdentifier> domRpcs = createDomRpcIdentifiers(path, rpcContextPaths);
95 final DOMRpcImplementationRegistration<?> domReg = domRpcRegistry.registerRpcImplementation(
96 new RpcAdapter(codec.getCodecRegistry(), type, implementation), domRpcs);
97 return new BindingDOMOperationAdapterRegistration<>(implementation, domReg);
100 private static Set<DOMRpcIdentifier> createDomRpcIdentifiers(final SchemaPath rpc,
101 final Collection<YangInstanceIdentifier> paths) {
102 final Set<DOMRpcIdentifier> ret = new HashSet<>();
103 for (final YangInstanceIdentifier path : paths) {
104 ret.add(DOMRpcIdentifier.create(rpc, path));
109 private Collection<YangInstanceIdentifier> toYangInstanceIdentifiers(final Set<InstanceIdentifier<?>> identifiers) {
110 final Collection<YangInstanceIdentifier> ret = new ArrayList<>(identifiers.size());
111 for (final InstanceIdentifier<?> binding : identifiers) {
112 ret.add(codec.toYangInstanceIdentifierCached(binding));
118 public <S extends Action<? extends TreeNode, ?, ?, ?>, T extends S, P extends TreeNode> ObjectRegistration<T>
119 registerActionImplementation(final Class<S> type, final T implementation,
120 final LogicalDatastoreType datastore, final Set<DataTreeIdentifier<P>> validNodes) {
121 final SchemaPath path = codec.getActionPath(type);
122 final ObjectRegistration<ActionAdapter> domReg = domActionRegistry.registerActionImplementation(
123 new ActionAdapter(codec.getCodecRegistry(), type, implementation),
124 DOMActionInstance.of(path, codec.toDOMDataTreeIdentifiers(validNodes)));
125 return new BindingDOMOperationAdapterRegistration<>(implementation, domReg);
128 public abstract static class AbstractImplAdapter<D> {
129 protected final BindingNormalizedNodeCodecRegistry codec;
130 protected final D delegate;
131 private final QName inputQname;
133 AbstractImplAdapter(final BindingNormalizedNodeCodecRegistry codec, final Class<? extends Operation> clazz,
135 this.codec = requireNonNull(codec);
136 this.delegate = requireNonNull(delegate);
137 inputQname = QName.create(BindingReflections.getQNameModule(clazz), "input").intern();
140 TreeNode deserialize(final SchemaPath path, final NormalizedNode<?, ?> input) {
141 if (input instanceof LazySerializedContainerNode) {
142 return ((LazySerializedContainerNode) input).bindingData();
144 final SchemaPath inputSchemaPath = path.createChild(inputQname);
145 return codec.fromNormalizedNodeOperationData(inputSchemaPath, (ContainerNode) input);
148 public static final class RpcAdapter extends AbstractImplAdapter<Rpc> implements DOMRpcImplementation {
150 RpcAdapter(BindingNormalizedNodeCodecRegistry codec, Class<? extends Operation> clazz,
151 Rpc<?, ?> delegate) {
152 super(codec, clazz, delegate);
155 @SuppressWarnings("checkstyle:illegalCatch, unchecked")
158 public FluentFuture<DOMRpcResult> invokeRpc(@Nonnull final DOMRpcIdentifier rpc,
159 @Nullable final NormalizedNode<?, ?> input) {
160 final TreeNode bindingInput = input != null ? deserialize(rpc.getType(), input) : null;
161 final SettableFuture<RpcResult<?>> bindingResult = SettableFuture.create();
162 CompletableFuture.runAsync(() -> delegate.invoke((Input<?>) bindingInput,
163 new RpcCallback<Output<?>>() {
164 public void onSuccess(Output<?> output) {
165 bindingResult.set(RpcResultBuilder.success(output).build());
168 public void onFailure(Throwable error) {
169 bindingResult.set(RpcResultBuilder.failed().withError(ErrorType.APPLICATION,
170 error.getMessage(), error).build());
174 return LazyDOMRpcResultFuture.create(codec,bindingResult);
178 public static final class ActionAdapter extends AbstractImplAdapter<Action>
179 implements DOMActionImplementation {
181 ActionAdapter(BindingNormalizedNodeCodecRegistry codec, Class<? extends Operation> clazz,
182 Action<?, ?, ?, ?> delegate) {
183 super(codec, clazz, delegate);
186 @SuppressWarnings("checkstyle:illegalCatch, unchecked")
188 public FluentFuture<? extends DOMActionResult> invokeAction(SchemaPath type, DOMDataTreeIdentifier path,
189 ContainerNode input) {
190 final TreeNode bindingInput = input != null ? deserialize(type, input) : null;
191 final SettableFuture<RpcResult<?>> bindingResult = SettableFuture.create();
192 CompletableFuture.runAsync(() -> delegate.invoke((Input<?>) bindingInput,
193 codec.fromYangInstanceIdentifier(path.getRootIdentifier()),
194 new RpcCallback<Output<?>>() {
195 public void onSuccess(Output<?> output) {
196 bindingResult.set(RpcResultBuilder.success(output).build());
199 public void onFailure(Throwable error) {
200 bindingResult.set(RpcResultBuilder.failed().withError(ErrorType.APPLICATION,
201 error.getMessage(), error).build());
205 return LazyDOMActionResultFuture.create(codec, bindingResult);