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