Introduce restconf.server.{api,spi,mdsal}
[netconf.git] / restconf / restconf-nb / src / main / java / org / opendaylight / restconf / nb / rfc8040 / rests / services / impl / RestconfInvokeOperationsServiceImpl.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.services.impl;
9
10 import static java.util.Objects.requireNonNull;
11
12 import java.io.InputStream;
13 import javax.ws.rs.Consumes;
14 import javax.ws.rs.Encoded;
15 import javax.ws.rs.POST;
16 import javax.ws.rs.Path;
17 import javax.ws.rs.PathParam;
18 import javax.ws.rs.Produces;
19 import javax.ws.rs.container.AsyncResponse;
20 import javax.ws.rs.container.Suspended;
21 import javax.ws.rs.core.Context;
22 import javax.ws.rs.core.MediaType;
23 import javax.ws.rs.core.Response;
24 import javax.ws.rs.core.UriInfo;
25 import org.opendaylight.restconf.nb.rfc8040.MediaTypes;
26 import org.opendaylight.restconf.nb.rfc8040.databind.JsonOperationInputBody;
27 import org.opendaylight.restconf.nb.rfc8040.databind.OperationInputBody;
28 import org.opendaylight.restconf.nb.rfc8040.databind.XmlOperationInputBody;
29 import org.opendaylight.restconf.nb.rfc8040.legacy.NormalizedNodePayload;
30 import org.opendaylight.restconf.server.spi.OperationOutput;
31
32 /**
33  * An operation resource represents a protocol operation defined with the YANG {@code rpc} statement. It is invoked
34  * using a POST method on the operation resource.
35  */
36 @Path("/")
37 public final class RestconfInvokeOperationsServiceImpl {
38     private final MdsalRestconfServer server;
39
40     public RestconfInvokeOperationsServiceImpl(final MdsalRestconfServer server) {
41         this.server = requireNonNull(server);
42     }
43
44     /**
45      * Invoke RPC operation.
46      *
47      * @param identifier module name and rpc identifier string for the desired operation
48      * @param body the body of the operation
49      * @param uriInfo URI info
50      * @param ar {@link AsyncResponse} which needs to be completed with a {@link NormalizedNodePayload} output
51      */
52     @POST
53     // FIXME: identifier is just a *single* QName
54     @Path("/operations/{identifier:.+}")
55     @Consumes({
56         MediaTypes.APPLICATION_YANG_DATA_XML,
57         MediaType.APPLICATION_XML,
58         MediaType.TEXT_XML
59     })
60     @Produces({
61         MediaTypes.APPLICATION_YANG_DATA_JSON,
62         MediaTypes.APPLICATION_YANG_DATA_XML,
63         MediaType.APPLICATION_JSON,
64         MediaType.APPLICATION_XML,
65         MediaType.TEXT_XML
66     })
67     public void invokeRpcXML(@Encoded @PathParam("identifier") final String identifier, final InputStream body,
68             @Context final UriInfo uriInfo, @Suspended final AsyncResponse ar) {
69         try (var xmlBody = new XmlOperationInputBody(body)) {
70             invokeRpc(identifier, uriInfo, ar, xmlBody);
71         }
72     }
73
74     /**
75      * Invoke RPC operation.
76      *
77      * @param identifier module name and rpc identifier string for the desired operation
78      * @param body the body of the operation
79      * @param uriInfo URI info
80      * @param ar {@link AsyncResponse} which needs to be completed with a {@link NormalizedNodePayload} output
81      */
82     @POST
83     // FIXME: identifier is just a *single* QName
84     @Path("/operations/{identifier:.+}")
85     @Consumes({
86         MediaTypes.APPLICATION_YANG_DATA_JSON,
87         MediaType.APPLICATION_JSON,
88     })
89     @Produces({
90         MediaTypes.APPLICATION_YANG_DATA_JSON,
91         MediaTypes.APPLICATION_YANG_DATA_XML,
92         MediaType.APPLICATION_JSON,
93         MediaType.APPLICATION_XML,
94         MediaType.TEXT_XML
95     })
96     public void invokeRpcJSON(@Encoded @PathParam("identifier") final String identifier, final InputStream body,
97             @Context final UriInfo uriInfo, @Suspended final AsyncResponse ar) {
98         try (var jsonBody = new JsonOperationInputBody(body)) {
99             invokeRpc(identifier, uriInfo, ar, jsonBody);
100         }
101     }
102
103     private void invokeRpc(final String identifier, final UriInfo uriInfo, final AsyncResponse ar,
104             final OperationInputBody body) {
105         server.invokeRpc(uriInfo.getBaseUri(), identifier, body)
106             .addCallback(new JaxRsRestconfCallback<OperationOutput>(ar) {
107                 @Override
108                 Response transform(final OperationOutput result) {
109                     final var body = result.output();
110                     return body == null ? Response.noContent().build()
111                         : Response.ok().entity(new NormalizedNodePayload(result.operation(), body)).build();
112                 }
113             });
114     }
115 }