blob: fd624c26be6438d642953d28e273d7aa4f916ecc [file] [log] [blame]
Henry Yue20926e2016-08-25 22:58:02 -04001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2016-present Open Networking Foundation
Henry Yue20926e2016-08-25 22:58:02 -04003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package org.onosproject.protocol.restconf.server.rpp;
18
19import com.fasterxml.jackson.core.JsonProcessingException;
20import com.fasterxml.jackson.databind.node.ObjectNode;
21import org.glassfish.jersey.server.ChunkedOutput;
Henry Yue20926e2016-08-25 22:58:02 -040022import org.onosproject.rest.AbstractWebResource;
Sean Condon13b16812018-01-25 10:31:49 +000023import org.onosproject.restconf.api.RestconfError;
Henry Yu3a91b132017-04-26 16:00:55 -040024import org.onosproject.restconf.api.RestconfException;
Henry Yuc10f7fc2017-07-26 13:42:08 -040025import org.onosproject.restconf.api.RestconfRpcOutput;
Henry Yu3a91b132017-04-26 16:00:55 -040026import org.onosproject.restconf.api.RestconfService;
Henry Yue20926e2016-08-25 22:58:02 -040027import org.slf4j.Logger;
28
Henry Yuc10f7fc2017-07-26 13:42:08 -040029import javax.servlet.http.HttpServletRequest;
Henry Yue20926e2016-08-25 22:58:02 -040030import javax.ws.rs.Consumes;
31import javax.ws.rs.DELETE;
32import javax.ws.rs.GET;
Dimitrios Mavrommatis89e60d72017-12-02 18:45:35 -080033import javax.ws.rs.PATCH;
Henry Yue20926e2016-08-25 22:58:02 -040034import javax.ws.rs.POST;
35import javax.ws.rs.PUT;
36import javax.ws.rs.Path;
37import javax.ws.rs.PathParam;
38import javax.ws.rs.Produces;
39import javax.ws.rs.core.Context;
40import javax.ws.rs.core.MediaType;
41import javax.ws.rs.core.Response;
42import javax.ws.rs.core.UriInfo;
43import java.io.IOException;
44import java.io.InputStream;
Henry Yuc10f7fc2017-07-26 13:42:08 -040045import java.net.URI;
Sean Condon13b16812018-01-25 10:31:49 +000046import java.util.Arrays;
Henry Yuc10f7fc2017-07-26 13:42:08 -040047import java.util.concurrent.CompletableFuture;
Henry Yue20926e2016-08-25 22:58:02 -040048
chengfanc58d4be2016-09-20 10:33:12 +080049import static javax.ws.rs.core.Response.Status.BAD_REQUEST;
50import static javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR;
Henry Yuc10f7fc2017-07-26 13:42:08 -040051import static javax.ws.rs.core.Response.Status.NOT_FOUND;
52import static javax.ws.rs.core.Response.Status.OK;
Ray Milkey86ee5e82018-04-02 15:33:07 -070053import static org.onlab.util.Tools.readTreeFromStream;
Henry Yue20926e2016-08-25 22:58:02 -040054import static org.slf4j.LoggerFactory.getLogger;
55
chengfanc58d4be2016-09-20 10:33:12 +080056
Henry Yue20926e2016-08-25 22:58:02 -040057/*
58 * This class is the main implementation of the RESTCONF Protocol
59 * Proxy module. Currently it only handles some basic operations
60 * on data resource nodes. However, the design intention is to
61 * create a code structure that allows new methods/functionality
62 * to be easily added in future releases.
63 */
64
65/**
66 * Implementation of the RESTCONF Protocol Proxy module.
67 */
68@Path("/")
69public class RestconfWebResource extends AbstractWebResource {
70
71 @Context
72 UriInfo uriInfo;
73
Henry Yu3a91b132017-04-26 16:00:55 -040074 private final RestconfService service = get(RestconfService.class);
Henry Yue20926e2016-08-25 22:58:02 -040075 private final Logger log = getLogger(getClass());
76
77 /**
78 * Handles a RESTCONF GET operation against a target data resource. If the
79 * operation is successful, the JSON presentation of the resource plus HTTP
Sean Condon13b16812018-01-25 10:31:49 +000080 * status code "200 OK" is returned. If it is not found then "404 Not Found"
81 * is returned. On internal error "500 Internal Server Error" is returned.
Henry Yue20926e2016-08-25 22:58:02 -040082 *
83 * @param uriString URI of the data resource.
Sean Condon13b16812018-01-25 10:31:49 +000084 * @return HTTP response - 200, 404 or 500
Henry Yue20926e2016-08-25 22:58:02 -040085 */
86 @GET
87 @Produces(MediaType.APPLICATION_JSON)
88 @Path("data/{identifier : .+}")
89 public Response handleGetRequest(@PathParam("identifier") String uriString) {
Henry Yue20926e2016-08-25 22:58:02 -040090 log.debug("handleGetRequest: {}", uriString);
91
Henry Yuc10f7fc2017-07-26 13:42:08 -040092 URI uri = uriInfo.getRequestUri();
93
Henry Yue20926e2016-08-25 22:58:02 -040094 try {
Henry Yuc10f7fc2017-07-26 13:42:08 -040095 ObjectNode node = service.runGetOperationOnDataResource(uri);
96 if (node == null) {
Sean Condon13b16812018-01-25 10:31:49 +000097 RestconfError error =
98 RestconfError.builder(RestconfError.ErrorType.PROTOCOL,
99 RestconfError.ErrorTag.INVALID_VALUE)
100 .errorMessage("Resource not found")
101 .errorPath(uriString)
102 .errorAppTag("handleGetRequest")
103 .build();
104 return Response.status(NOT_FOUND)
105 .entity(RestconfError.wrapErrorAsJson(Arrays.asList(error))).build();
Henry Yuc10f7fc2017-07-26 13:42:08 -0400106 }
Henry Yue20926e2016-08-25 22:58:02 -0400107 return ok(node).build();
108 } catch (RestconfException e) {
109 log.error("ERROR: handleGetRequest: {}", e.getMessage());
110 log.debug("Exception in handleGetRequest:", e);
Sean Condon13b16812018-01-25 10:31:49 +0000111 return Response.status(e.getResponse().getStatus()).entity(e.toRestconfErrorJson()).build();
112 } catch (Exception e) {
113 RestconfError error = RestconfError
114 .builder(RestconfError.ErrorType.APPLICATION, RestconfError.ErrorTag.OPERATION_FAILED)
115 .errorMessage(e.getMessage()).errorAppTag("handlePostRequest").build();
116 return Response.status(INTERNAL_SERVER_ERROR)
117 .entity(RestconfError.wrapErrorAsJson(Arrays.asList(error))).build();
Henry Yue20926e2016-08-25 22:58:02 -0400118 }
119 }
120
121 /**
122 * Handles the RESTCONF Event Notification Subscription request. If the
123 * subscription is successful, a ChunkedOutput stream is created and returned
124 * to the caller.
Yuta HIGUCHId1ce4bc2017-06-03 01:05:33 -0700125 * <p>
Henry Yue20926e2016-08-25 22:58:02 -0400126 * This function is not blocked on streaming the data (so that it can handle
127 * other incoming requests). Instead, a worker thread running in the background
128 * does the data streaming. If errors occur during streaming, the worker thread
129 * calls ChunkedOutput.close() to disconnect the session and terminates itself.
130 *
131 * @param streamId Event stream ID
Henry Yuc10f7fc2017-07-26 13:42:08 -0400132 * @param request RESTCONF client information from which the client IP
133 * address is retrieved
Henry Yue20926e2016-08-25 22:58:02 -0400134 * @return A string data stream over HTTP keep-alive session
135 */
136 @GET
137 @Produces(MediaType.APPLICATION_JSON)
138 @Path("streams/{streamId}")
Henry Yuc10f7fc2017-07-26 13:42:08 -0400139 public ChunkedOutput<String> handleNotificationRegistration(@PathParam("streamId") String streamId,
140 @Context HttpServletRequest request) {
Yuta HIGUCHId1ce4bc2017-06-03 01:05:33 -0700141 final ChunkedOutput<String> output = new ChunkedOutput<>(String.class);
Henry Yue20926e2016-08-25 22:58:02 -0400142 try {
Henry Yuc10f7fc2017-07-26 13:42:08 -0400143 service.subscribeEventStream(streamId, request.getRemoteAddr(), output);
Henry Yue20926e2016-08-25 22:58:02 -0400144 } catch (RestconfException e) {
145 log.error("ERROR: handleNotificationRegistration: {}", e.getMessage());
146 log.debug("Exception in handleNotificationRegistration:", e);
147 try {
148 output.close();
149 } catch (IOException ex) {
150 log.error("ERROR: handleNotificationRegistration:", ex);
151 }
152 }
153
154 return output;
155 }
156
157 /**
Henry Yuc10f7fc2017-07-26 13:42:08 -0400158 * Handles a RESTCONF POST operation against the entire data store. If the
159 * operation is successful, HTTP status code "201 Created" is returned
160 * and there is no response message-body. If the data resource already
161 * exists, then the HTTP status code "409 Conflict" is returned.
162 *
163 * @param stream Input JSON object
164 * @return HTTP response
165 */
166 @POST
167 @Consumes(MediaType.APPLICATION_JSON)
168 @Produces(MediaType.APPLICATION_JSON)
169 @Path("data")
170 public Response handlePostDatastore(InputStream stream) {
171
172 log.debug("handlePostDatastore");
173 return handlePostRequest(null, stream);
174 }
175
176 /**
Henry Yue20926e2016-08-25 22:58:02 -0400177 * Handles a RESTCONF POST operation against a data resource. If the
178 * operation is successful, HTTP status code "201 Created" is returned
179 * and there is no response message-body. If the data resource already
180 * exists, then the HTTP status code "409 Conflict" is returned.
181 *
Henry Yuc10f7fc2017-07-26 13:42:08 -0400182 * @param uriString URI of the parent data resource
Henry Yue20926e2016-08-25 22:58:02 -0400183 * @param stream Input JSON object
184 * @return HTTP response
185 */
186 @POST
187 @Consumes(MediaType.APPLICATION_JSON)
188 @Produces(MediaType.APPLICATION_JSON)
189 @Path("data/{identifier : .+}")
chengfanc58d4be2016-09-20 10:33:12 +0800190 public Response handlePostRequest(@PathParam("identifier") String uriString,
191 InputStream stream) {
Henry Yue20926e2016-08-25 22:58:02 -0400192 log.debug("handlePostRequest: {}", uriString);
193
Henry Yuc10f7fc2017-07-26 13:42:08 -0400194 URI uri = uriInfo.getRequestUri();
195
Henry Yue20926e2016-08-25 22:58:02 -0400196 try {
Ray Milkey86ee5e82018-04-02 15:33:07 -0700197 ObjectNode rootNode = readTreeFromStream(mapper(), stream);
Henry Yue20926e2016-08-25 22:58:02 -0400198
Henry Yuc10f7fc2017-07-26 13:42:08 -0400199 service.runPostOperationOnDataResource(uri, rootNode);
Henry Yue20926e2016-08-25 22:58:02 -0400200 return Response.created(uriInfo.getRequestUri()).build();
201 } catch (JsonProcessingException e) {
202 log.error("ERROR: handlePostRequest ", e);
Sean Condon13b16812018-01-25 10:31:49 +0000203 RestconfError error = RestconfError
204 .builder(RestconfError.ErrorType.APPLICATION, RestconfError.ErrorTag.MALFORMED_MESSAGE)
205 .errorMessage(e.getMessage()).errorAppTag("handlePostRequest").build();
206 return Response.status(BAD_REQUEST)
207 .entity(RestconfError.wrapErrorAsJson(Arrays.asList(error))).build();
Henry Yue20926e2016-08-25 22:58:02 -0400208 } catch (RestconfException e) {
209 log.error("ERROR: handlePostRequest: {}", e.getMessage());
210 log.debug("Exception in handlePostRequest:", e);
Sean Condon13b16812018-01-25 10:31:49 +0000211 return Response.status(e.getResponse().getStatus())
212 .entity(e.toRestconfErrorJson()).build();
Henry Yue20926e2016-08-25 22:58:02 -0400213 } catch (IOException ex) {
214 log.error("ERROR: handlePostRequest ", ex);
Sean Condon13b16812018-01-25 10:31:49 +0000215 RestconfError error = RestconfError
216 .builder(RestconfError.ErrorType.APPLICATION, RestconfError.ErrorTag.OPERATION_FAILED)
217 .errorMessage(ex.getMessage()).errorAppTag("handlePostRequest").build();
218 return Response.status(INTERNAL_SERVER_ERROR)
219 .entity(RestconfError.wrapErrorAsJson(Arrays.asList(error))).build();
Henry Yue20926e2016-08-25 22:58:02 -0400220 }
221 }
222
223 /**
Henry Yuc10f7fc2017-07-26 13:42:08 -0400224 * Handles a RESTCONF RPC request. This function executes the RPC in
225 * the target application's context and returns the results as a Future.
226 *
227 * @param rpcName Name of the RPC
228 * @param rpcInput Input parameters
229 * @param request RESTCONF client information from which the client IP
230 * address is retrieved
231 * @return RPC output
232 */
233 @POST
234 @Consumes(MediaType.APPLICATION_JSON)
235 @Produces(MediaType.APPLICATION_JSON)
236 @Path("operations/{rpc : .+}")
237 public Response handleRpcRequest(@PathParam("rpc") String rpcName,
238 InputStream rpcInput,
239 @Context HttpServletRequest request) {
240 URI uri = uriInfo.getRequestUri();
241 try {
Ray Milkey86ee5e82018-04-02 15:33:07 -0700242 ObjectNode inputNode = readTreeFromStream(mapper(), rpcInput);
Henry Yuc10f7fc2017-07-26 13:42:08 -0400243 CompletableFuture<RestconfRpcOutput> rpcFuture = service.runRpc(uri,
244 inputNode,
245 request.getRemoteAddr());
246 RestconfRpcOutput restconfRpcOutput;
247 restconfRpcOutput = rpcFuture.get();
248 if (restconfRpcOutput.status() != OK) {
249 return Response.status(restconfRpcOutput.status())
250 .entity(restconfRpcOutput.reason()).build();
251 }
252 ObjectNode node = restconfRpcOutput.output();
253 return ok(node).build();
254 } catch (JsonProcessingException e) {
255 log.error("ERROR: handleRpcRequest", e);
Sean Condon13b16812018-01-25 10:31:49 +0000256 RestconfError error = RestconfError
257 .builder(RestconfError.ErrorType.APPLICATION, RestconfError.ErrorTag.MALFORMED_MESSAGE)
258 .errorMessage(e.getMessage()).errorAppTag("handleRpcRequest").build();
259 return Response.status(BAD_REQUEST)
260 .entity(RestconfError.wrapErrorAsJson(Arrays.asList(error))).build();
Henry Yuc10f7fc2017-07-26 13:42:08 -0400261 } catch (RestconfException e) {
262 log.error("ERROR: handleRpcRequest: {}", e.getMessage());
263 log.debug("Exception in handleRpcRequest:", e);
Sean Condon13b16812018-01-25 10:31:49 +0000264 return Response.status(e.getResponse().getStatus())
265 .entity(e.toRestconfErrorJson()).build();
Henry Yuc10f7fc2017-07-26 13:42:08 -0400266 } catch (Exception e) {
267 log.error("ERROR: handleRpcRequest ", e);
Sean Condon13b16812018-01-25 10:31:49 +0000268 RestconfError error = RestconfError
269 .builder(RestconfError.ErrorType.APPLICATION, RestconfError.ErrorTag.OPERATION_FAILED)
270 .errorMessage(e.getMessage()).errorAppTag("handleRpcRequest").build();
271 return Response.status(INTERNAL_SERVER_ERROR)
272 .entity(RestconfError.wrapErrorAsJson(Arrays.asList(error))).build();
Henry Yuc10f7fc2017-07-26 13:42:08 -0400273 }
274 }
275
276 /**
Henry Yue20926e2016-08-25 22:58:02 -0400277 * Handles a RESTCONF PUT operation against a data resource. If a new
278 * resource is successfully created, then the HTTP status code "201 Created"
279 * is returned. If an existing resource is modified, then the HTTP
280 * status code "204 No Content" is returned. If the input JSON payload
281 * contains errors, then "400 Bad Request" is returned. If an exception
282 * occurs during the operation, the status code enclosed in
283 * the RestconfException object, such as "500 Internal Server Error",
284 * is returned.
285 *
286 * @param uriString URI of the data resource.
287 * @param stream Input JSON object
288 * @return HTTP response
289 */
290 @PUT
291 @Consumes(MediaType.APPLICATION_JSON)
292 @Produces(MediaType.APPLICATION_JSON)
293 @Path("data/{identifier : .+}")
chengfanc58d4be2016-09-20 10:33:12 +0800294 public Response handlePutRequest(@PathParam("identifier") String uriString,
295 InputStream stream) {
Henry Yue20926e2016-08-25 22:58:02 -0400296 log.debug("handlePutRequest: {}", uriString);
297
Henry Yuc10f7fc2017-07-26 13:42:08 -0400298 URI uri = uriInfo.getRequestUri();
299
Henry Yue20926e2016-08-25 22:58:02 -0400300 try {
Ray Milkey86ee5e82018-04-02 15:33:07 -0700301 ObjectNode rootNode = readTreeFromStream(mapper(), stream);
Henry Yue20926e2016-08-25 22:58:02 -0400302
Henry Yuc10f7fc2017-07-26 13:42:08 -0400303 service.runPutOperationOnDataResource(uri, rootNode);
Henry Yue20926e2016-08-25 22:58:02 -0400304 return Response.created(uriInfo.getRequestUri()).build();
305 } catch (JsonProcessingException e) {
306 log.error("ERROR: handlePutRequest ", e);
Sean Condon13b16812018-01-25 10:31:49 +0000307 RestconfError error = RestconfError
308 .builder(RestconfError.ErrorType.APPLICATION, RestconfError.ErrorTag.MALFORMED_MESSAGE)
309 .errorMessage(e.getMessage()).errorAppTag("handlePutRequest").build();
310 return Response.status(BAD_REQUEST)
311 .entity(RestconfError.wrapErrorAsJson(Arrays.asList(error))).build();
Henry Yue20926e2016-08-25 22:58:02 -0400312 } catch (RestconfException e) {
313 log.error("ERROR: handlePutRequest: {}", e.getMessage());
314 log.debug("Exception in handlePutRequest:", e);
Sean Condon13b16812018-01-25 10:31:49 +0000315 return Response.status(e.getResponse().getStatus())
316 .entity(e.toRestconfErrorJson()).build();
Henry Yue20926e2016-08-25 22:58:02 -0400317 } catch (IOException ex) {
318 log.error("ERROR: handlePutRequest ", ex);
Sean Condon13b16812018-01-25 10:31:49 +0000319 RestconfError error = RestconfError
320 .builder(RestconfError.ErrorType.APPLICATION, RestconfError.ErrorTag.OPERATION_FAILED)
321 .errorMessage(ex.getMessage()).errorAppTag("handlePutRequest").build();
322 return Response.status(INTERNAL_SERVER_ERROR)
323 .entity(RestconfError.wrapErrorAsJson(Arrays.asList(error))).build();
Henry Yue20926e2016-08-25 22:58:02 -0400324 }
325 }
326
327 /**
328 * Handles the RESTCONF DELETION Operation against a data resource. If the
329 * resource is successfully deleted, the HTTP status code "204 No Content"
330 * is returned in the response. If an exception occurs, then the
331 * HTTP status code enclosed in the RestconfException object is
332 * returned.
333 *
334 * @param uriString URI of the data resource to be deleted.
335 * @return HTTP response
336 */
337 @DELETE
338 @Produces(MediaType.APPLICATION_JSON)
339 @Path("data/{identifier : .+}")
340 public Response handleDeleteRequest(@PathParam("identifier") String uriString) {
Henry Yue20926e2016-08-25 22:58:02 -0400341 log.debug("handleDeleteRequest: {}", uriString);
342
Henry Yuc10f7fc2017-07-26 13:42:08 -0400343 URI uri = uriInfo.getRequestUri();
344
Henry Yue20926e2016-08-25 22:58:02 -0400345 try {
Henry Yuc10f7fc2017-07-26 13:42:08 -0400346 service.runDeleteOperationOnDataResource(uri);
Henry Yue20926e2016-08-25 22:58:02 -0400347 return Response.ok().build();
348 } catch (RestconfException e) {
349 log.error("ERROR: handleDeleteRequest: {}", e.getMessage());
350 log.debug("Exception in handleDeleteRequest:", e);
Sean Condon13b16812018-01-25 10:31:49 +0000351 return Response.status(e.getResponse().getStatus())
352 .entity(e.toRestconfErrorJson()).build();
Henry Yue20926e2016-08-25 22:58:02 -0400353 }
354 }
355
chengfanc58d4be2016-09-20 10:33:12 +0800356 /**
357 * Handles a RESTCONF PATCH operation against a data resource.
358 * If the PATCH request succeeds, a "200 OK" status-line is returned if
359 * there is a message-body, and "204 No Content" is returned if no
360 * response message-body is sent.
361 *
Henry Yuc10f7fc2017-07-26 13:42:08 -0400362 * @param uriString URI of the parent data resource
chengfanc58d4be2016-09-20 10:33:12 +0800363 * @param stream Input JSON object
364 * @return HTTP response
365 */
Dimitrios Mavrommatis89e60d72017-12-02 18:45:35 -0800366 @PATCH
chengfanc58d4be2016-09-20 10:33:12 +0800367 @Consumes(MediaType.APPLICATION_JSON)
368 @Produces(MediaType.APPLICATION_JSON)
369 @Path("data/{identifier : .+}")
370 public Response handlePatchRequest(@PathParam("identifier") String uriString,
371 InputStream stream) {
372
373 log.debug("handlePatchRequest: {}", uriString);
374
Henry Yuc10f7fc2017-07-26 13:42:08 -0400375 URI uri = uriInfo.getRequestUri();
376
chengfanc58d4be2016-09-20 10:33:12 +0800377 try {
Ray Milkey86ee5e82018-04-02 15:33:07 -0700378 ObjectNode rootNode = readTreeFromStream(mapper(), stream);
chengfanc58d4be2016-09-20 10:33:12 +0800379
Henry Yuc10f7fc2017-07-26 13:42:08 -0400380 service.runPatchOperationOnDataResource(uri, rootNode);
chengfanc58d4be2016-09-20 10:33:12 +0800381 return Response.ok().build();
382 } catch (JsonProcessingException e) {
383 log.error("ERROR: handlePatchRequest ", e);
Sean Condon13b16812018-01-25 10:31:49 +0000384 RestconfError error = RestconfError
385 .builder(RestconfError.ErrorType.APPLICATION, RestconfError.ErrorTag.MALFORMED_MESSAGE)
386 .errorMessage(e.getMessage()).errorAppTag("handlePatchRequest").build();
387 return Response.status(BAD_REQUEST)
388 .entity(RestconfError.wrapErrorAsJson(Arrays.asList(error))).build();
chengfanc58d4be2016-09-20 10:33:12 +0800389 } catch (RestconfException e) {
390 log.error("ERROR: handlePatchRequest: {}", e.getMessage());
391 log.debug("Exception in handlePatchRequest:", e);
Sean Condon13b16812018-01-25 10:31:49 +0000392 return Response.status(e.getResponse().getStatus())
393 .entity(e.toRestconfErrorJson()).build();
chengfanc58d4be2016-09-20 10:33:12 +0800394 } catch (IOException ex) {
395 log.error("ERROR: handlePatchRequest ", ex);
Sean Condon13b16812018-01-25 10:31:49 +0000396 RestconfError error = RestconfError
397 .builder(RestconfError.ErrorType.APPLICATION, RestconfError.ErrorTag.OPERATION_FAILED)
398 .errorMessage(ex.getMessage()).errorAppTag("handlePatchRequest").build();
399 return Response.status(INTERNAL_SERVER_ERROR)
400 .entity(RestconfError.wrapErrorAsJson(Arrays.asList(error))).build();
chengfanc58d4be2016-09-20 10:33:12 +0800401 }
402 }
403
Henry Yuc10f7fc2017-07-26 13:42:08 -0400404
405 /**
406 * Handles a RESTCONF PATCH operation against the entire data store.
407 * If the PATCH request succeeds, a "200 OK" status-line is returned if
408 * there is a message-body, and "204 No Content" is returned if no
409 * response message-body is sent.
410 *
411 * @param stream Input JSON object
412 * @return HTTP response
413 */
Dimitrios Mavrommatis89e60d72017-12-02 18:45:35 -0800414 @PATCH
Henry Yuc10f7fc2017-07-26 13:42:08 -0400415 @Consumes(MediaType.APPLICATION_JSON)
416 @Produces(MediaType.APPLICATION_JSON)
417 @Path("data")
418 public Response handlePatchDatastore(InputStream stream) {
419 log.debug("handlePatchDatastore");
420 return handlePatchRequest(null, stream);
421 }
Henry Yue20926e2016-08-25 22:58:02 -0400422}