8e1304ea5bfb8682b4683746c4dcd2da6f3d4959
[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.ArrayList;
12 import java.util.List;
13 import java.util.Optional;
14 import java.util.concurrent.CancellationException;
15 import javax.ws.rs.core.Response.Status;
16 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
17 import org.opendaylight.mdsal.dom.api.DOMActionResult;
18 import org.opendaylight.mdsal.dom.api.DOMActionService;
19 import org.opendaylight.mdsal.dom.api.DOMDataTreeIdentifier;
20 import org.opendaylight.mdsal.dom.api.DOMMountPoint;
21 import org.opendaylight.mdsal.dom.api.DOMRpcResult;
22 import org.opendaylight.mdsal.dom.api.DOMRpcService;
23 import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
24 import org.opendaylight.restconf.common.errors.RestconfError.ErrorTag;
25 import org.opendaylight.restconf.common.errors.RestconfError.ErrorType;
26 import org.opendaylight.restconf.nb.rfc8040.handlers.ActionServiceHandler;
27 import org.opendaylight.restconf.nb.rfc8040.handlers.RpcServiceHandler;
28 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
29 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
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.model.api.SchemaPath;
33 import org.slf4j.Logger;
34 import org.slf4j.LoggerFactory;
35
36 /**
37  * Util class for rpc.
38  *
39  */
40 public final class RestconfInvokeOperationsUtil {
41
42     private static final Logger LOG = LoggerFactory.getLogger(RestconfInvokeOperationsUtil.class);
43
44     private RestconfInvokeOperationsUtil() {
45         throw new UnsupportedOperationException("Util class");
46     }
47
48     /**
49      * Invoking rpc via mount point.
50      *
51      * @param mountPoint
52      *             mount point
53      * @param data
54      *             input data
55      * @param schemaPath
56      *             schema path of data
57      * @return {@link DOMRpcResult}
58      */
59     public static DOMRpcResult invokeRpcViaMountPoint(final DOMMountPoint mountPoint, final NormalizedNode<?, ?> data,
60             final SchemaPath schemaPath) {
61         final Optional<DOMRpcService> mountPointService = mountPoint.getService(DOMRpcService.class);
62         if (mountPointService.isPresent()) {
63             final ListenableFuture<DOMRpcResult> rpc = mountPointService.get().invokeRpc(schemaPath, data);
64             return prepareResult(rpc);
65         }
66         final String errmsg = "RPC service is missing.";
67         LOG.debug(errmsg);
68         throw new RestconfDocumentedException(errmsg);
69     }
70
71     /**
72      * Invoke rpc.
73      *
74      * @param data
75      *             input data
76      * @param schemaPath
77      *             schema path of data
78      * @param rpcServiceHandler
79      *             rpc service handler to invoke rpc
80      * @return {@link DOMRpcResult}
81      */
82     public static DOMRpcResult invokeRpc(final NormalizedNode<?, ?> data, final SchemaPath schemaPath,
83             final RpcServiceHandler rpcServiceHandler) {
84         final DOMRpcService rpcService = rpcServiceHandler.get();
85         if (rpcService == null) {
86             throw new RestconfDocumentedException(Status.SERVICE_UNAVAILABLE);
87         }
88
89         final ListenableFuture<DOMRpcResult> rpc = rpcService.invokeRpc(schemaPath, data);
90         return prepareResult(rpc);
91     }
92
93     /**
94      * Check the validity of the result.
95      *
96      * @param response
97      *             response of rpc
98      * @return {@link DOMRpcResult} result
99      */
100     public static DOMRpcResult checkResponse(final DOMRpcResult response) {
101         if (response == null) {
102             return null;
103         }
104         try {
105             if (response.getErrors().isEmpty()) {
106                 return response;
107             }
108             LOG.debug("RpcError message {}", response.getErrors());
109             throw new RestconfDocumentedException("RPCerror message ", null, response.getErrors());
110         } catch (final CancellationException e) {
111             final String errMsg = "The operation was cancelled while executing.";
112             LOG.debug("Cancel RpcExecution: {}", errMsg, e);
113             throw new RestconfDocumentedException(errMsg, ErrorType.RPC, ErrorTag.PARTIAL_OPERATION, e);
114         }
115     }
116
117     private static DOMRpcResult prepareResult(final ListenableFuture<DOMRpcResult> rpc) {
118         final RpcResultFactory dataFactory = new RpcResultFactory();
119         FutureCallbackTx.addCallback(rpc, RestconfDataServiceConstant.PostData.POST_TX_TYPE, dataFactory);
120         return dataFactory.build();
121     }
122
123     /**
124      * Invoking Action via mount point.
125      *
126      * @param mountPoint
127      *             mount point
128      * @param data
129      *             input data
130      * @param schemaPath
131      *             schema path of data
132      * @return {@link DOMActionResult}
133      */
134     public static DOMActionResult invokeActionViaMountPoint(final DOMMountPoint mountPoint, final ContainerNode data,
135             final SchemaPath schemaPath, final YangInstanceIdentifier yangIId) {
136         final Optional<DOMActionService> mountPointService = mountPoint.getService(DOMActionService.class);
137         if (!mountPointService.isPresent()) {
138             throw new RestconfDocumentedException("DomAction service is missing.");
139         }
140
141         return prepareActionResult(mountPointService.get().invokeAction(schemaPath,
142             prepareDataTreeId(yangIId, schemaPath), 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 SchemaPath schemaPath,
157             final ActionServiceHandler actionServiceHandler, final YangInstanceIdentifier yangIId) {
158         return prepareActionResult(actionServiceHandler.get().invokeAction(schemaPath,
159             prepareDataTreeId(yangIId, schemaPath), 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, RestconfDataServiceConstant.PostData.POST_TX_TYPE, dataFactory);
196         return dataFactory.build();
197     }
198
199     /**
200      * Prepare DOMDataTree Identifier.
201      *
202      * @param yangIId
203      *             {@link YangInstanceIdentifier}
204      * @param schemaPath
205      *              {@link SchemaPath}
206      * @return {@link DOMDataTreeIdentifier} domDataTreeIdentifier
207      */
208     private static DOMDataTreeIdentifier prepareDataTreeId(final YangInstanceIdentifier yangIId,
209             final SchemaPath schemaPath) {
210         final List<PathArgument> pathArg = new ArrayList<>();
211         for (PathArgument path : yangIId.getPathArguments()) {
212             if (path.getNodeType().getLocalName().equals(schemaPath.getLastComponent().getLocalName())) {
213                 break;
214             }
215             pathArg.add(path);
216         }
217         YangInstanceIdentifier yangInstanceIdentifier = YangInstanceIdentifier.builder().append(pathArg).build();
218         DOMDataTreeIdentifier domDataTreeIdentifier = new DOMDataTreeIdentifier(LogicalDatastoreType.OPERATIONAL,
219             yangInstanceIdentifier);
220         return domDataTreeIdentifier;
221     }
222 }