8bef7a3f46c83fdd37fa70b266c7ef9d14024721
[netconf.git] / restconf / restconf-nb-rfc8040 / src / main / java / org / opendaylight / restconf / nb / rfc8040 / rests / utils / RestconfInvokeOperationsUtil.java
1 /*
2  * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.restconf.nb.rfc8040.rests.utils;
9
10 import com.google.common.util.concurrent.ListenableFuture;
11 import java.util.Optional;
12 import java.util.concurrent.CancellationException;
13 import javax.ws.rs.core.Response.Status;
14 import org.eclipse.jdt.annotation.NonNull;
15 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
16 import org.opendaylight.mdsal.dom.api.DOMActionResult;
17 import org.opendaylight.mdsal.dom.api.DOMActionService;
18 import org.opendaylight.mdsal.dom.api.DOMDataTreeIdentifier;
19 import org.opendaylight.mdsal.dom.api.DOMMountPoint;
20 import org.opendaylight.mdsal.dom.api.DOMRpcResult;
21 import org.opendaylight.mdsal.dom.api.DOMRpcService;
22 import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
23 import org.opendaylight.restconf.common.errors.RestconfError.ErrorTag;
24 import org.opendaylight.restconf.common.errors.RestconfError.ErrorType;
25 import org.opendaylight.restconf.nb.rfc8040.handlers.ActionServiceHandler;
26 import org.opendaylight.restconf.nb.rfc8040.handlers.RpcServiceHandler;
27 import org.opendaylight.yangtools.yang.common.QName;
28 import org.opendaylight.yangtools.yang.common.YangConstants;
29 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
30 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
31 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
32 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
33 import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier.Absolute;
34 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory;
36
37 /**
38  * Util class for rpc.
39  */
40 public final class RestconfInvokeOperationsUtil {
41     private static final Logger LOG = LoggerFactory.getLogger(RestconfInvokeOperationsUtil.class);
42
43     private RestconfInvokeOperationsUtil() {
44         throw new UnsupportedOperationException("Util class");
45     }
46
47     /**
48      * Invoking rpc via mount point.
49      *
50      * @param mountPoint
51      *             mount point
52      * @param data
53      *             input data
54      * @param schemaPath
55      *             schema path of data
56      * @return {@link DOMRpcResult}
57      */
58     public static DOMRpcResult invokeRpcViaMountPoint(final DOMMountPoint mountPoint, final NormalizedNode<?, ?> data,
59             final QName schemaPath) {
60         final Optional<DOMRpcService> mountPointService = mountPoint.getService(DOMRpcService.class);
61         if (mountPointService.isPresent()) {
62             return prepareResult(mountPointService.get().invokeRpc(schemaPath, nonnullInput(schemaPath, data)));
63         }
64         final String errmsg = "RPC service is missing.";
65         LOG.debug(errmsg);
66         throw new RestconfDocumentedException(errmsg);
67     }
68
69     /**
70      * Invoke rpc.
71      *
72      * @param data
73      *             input data
74      * @param rpc
75      *             RPC type
76      * @param rpcServiceHandler
77      *             rpc service handler to invoke rpc
78      * @return {@link DOMRpcResult}
79      */
80     public static DOMRpcResult invokeRpc(final NormalizedNode<?, ?> data, final QName rpc,
81             final RpcServiceHandler rpcServiceHandler) {
82         final DOMRpcService rpcService = rpcServiceHandler.get();
83         if (rpcService == null) {
84             throw new RestconfDocumentedException(Status.SERVICE_UNAVAILABLE);
85         }
86
87         return prepareResult(rpcService.invokeRpc(rpc, nonnullInput(rpc, data)));
88     }
89
90     private static @NonNull NormalizedNode<?, ?> nonnullInput(final QName type, final NormalizedNode<?, ?> input) {
91         return input != null ? input
92                 : ImmutableNodes.containerNode(YangConstants.operationInputQName(type.getModule()));
93     }
94
95     /**
96      * Check the validity of the result.
97      *
98      * @param response
99      *             response of rpc
100      * @return {@link DOMRpcResult} result
101      */
102     public static DOMRpcResult checkResponse(final DOMRpcResult response) {
103         if (response == null) {
104             return null;
105         }
106         try {
107             if (response.getErrors().isEmpty()) {
108                 return response;
109             }
110             LOG.debug("RpcError message {}", response.getErrors());
111             throw new RestconfDocumentedException("RPCerror message ", null, response.getErrors());
112         } catch (final CancellationException e) {
113             final String errMsg = "The operation was cancelled while executing.";
114             LOG.debug("Cancel RpcExecution: {}", errMsg, e);
115             throw new RestconfDocumentedException(errMsg, ErrorType.RPC, ErrorTag.PARTIAL_OPERATION, e);
116         }
117     }
118
119     private static DOMRpcResult prepareResult(final ListenableFuture<? extends DOMRpcResult> rpc) {
120         final RpcResultFactory dataFactory = new RpcResultFactory();
121         FutureCallbackTx.addCallback(rpc, PostDataTransactionUtil.POST_TX_TYPE, dataFactory);
122         return dataFactory.build();
123     }
124
125     /**
126      * Invoking Action via mount point.
127      *
128      * @param mountPoint
129      *             mount point
130      * @param data
131      *             input data
132      * @param schemaPath
133      *             schema path of data
134      * @return {@link DOMActionResult}
135      */
136     public static DOMActionResult invokeActionViaMountPoint(final DOMMountPoint mountPoint, final ContainerNode data,
137             final Absolute schemaPath, final YangInstanceIdentifier yangIId) {
138         final Optional<DOMActionService> mountPointService = mountPoint.getService(DOMActionService.class);
139         if (!mountPointService.isPresent()) {
140             throw new RestconfDocumentedException("DomAction service is missing.");
141         }
142         return prepareActionResult(mountPointService.get().invokeAction(schemaPath, prepareDataTreeId(yangIId), data));
143     }
144
145     /**
146      * Invoke Action via ActionServiceHandler.
147      *
148      * @param data
149      *             input data
150      * @param schemaPath
151      *             schema path of data
152      * @param actionServiceHandler
153      *             action service handler to invoke action
154      * @return {@link DOMActionResult}
155      */
156     public static DOMActionResult invokeAction(final ContainerNode data, final Absolute schemaPath,
157             final ActionServiceHandler actionServiceHandler, final YangInstanceIdentifier yangIId) {
158         return prepareActionResult(
159             actionServiceHandler.get().invokeAction(schemaPath, prepareDataTreeId(yangIId), data));
160     }
161
162     /**
163      * Check the validity of the result.
164      *
165      * @param response
166      *             response of Action
167      * @return {@link DOMActionResult} result
168      */
169     public static DOMActionResult checkActionResponse(final DOMActionResult response) {
170         if (response != null) {
171             try {
172                 if (response.getErrors().isEmpty()) {
173                     return response;
174                 }
175                 LOG.debug("InvokeAction Error Message {}", response.getErrors());
176                 throw new RestconfDocumentedException("InvokeAction Error Message ", null, response.getErrors());
177             } catch (final CancellationException e) {
178                 final String errMsg = "The Action Operation was cancelled while executing.";
179                 LOG.debug("Cancel Execution: {}", errMsg, e);
180                 throw new RestconfDocumentedException(errMsg, ErrorType.RPC, ErrorTag.PARTIAL_OPERATION, e);
181             }
182         }
183         return null;
184     }
185
186     /**
187      * Prepare Action Result.
188      *
189      * @param actionResult
190      *            {@link DOMActionResult} - action result
191      * @return {@link DOMActionResult} result
192      */
193     private static DOMActionResult prepareActionResult(final ListenableFuture<? extends DOMActionResult> actionResult) {
194         final ActionResultFactory dataFactory = new ActionResultFactory();
195         FutureCallbackTx.addCallback(actionResult, PostDataTransactionUtil.POST_TX_TYPE, dataFactory);
196         return dataFactory.build();
197     }
198
199     /**
200      * Prepare DOMDataTree Identifier.
201      *
202      * @param yangIId {@link YangInstanceIdentifier}
203      * @return {@link DOMDataTreeIdentifier} domDataTreeIdentifier
204      */
205     private static DOMDataTreeIdentifier prepareDataTreeId(final YangInstanceIdentifier yangIId) {
206         return new DOMDataTreeIdentifier(LogicalDatastoreType.OPERATIONAL, yangIId.getParent());
207     }
208 }