blob: 35abdb026e31a82fabb61541efd8974d1d768112 [file] [log] [blame]
Henry Yue20926e2016-08-25 22:58:02 -04001/*
2 * Copyright 2016-present Open Networking Laboratory
3 *
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;
chengfanc58d4be2016-09-20 10:33:12 +080022import org.onosproject.protocol.restconf.server.api.Patch;
Henry Yue20926e2016-08-25 22:58:02 -040023import org.onosproject.protocol.restconf.server.api.RestconfException;
24import org.onosproject.protocol.restconf.server.api.RestconfService;
25import org.onosproject.rest.AbstractWebResource;
26import org.slf4j.Logger;
27
28import javax.ws.rs.Consumes;
29import javax.ws.rs.DELETE;
30import javax.ws.rs.GET;
31import javax.ws.rs.POST;
32import javax.ws.rs.PUT;
33import javax.ws.rs.Path;
34import javax.ws.rs.PathParam;
35import javax.ws.rs.Produces;
36import javax.ws.rs.core.Context;
37import javax.ws.rs.core.MediaType;
38import javax.ws.rs.core.Response;
39import javax.ws.rs.core.UriInfo;
40import java.io.IOException;
41import java.io.InputStream;
42
chengfanc58d4be2016-09-20 10:33:12 +080043import static javax.ws.rs.core.Response.Status.BAD_REQUEST;
44import static javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR;
Henry Yue20926e2016-08-25 22:58:02 -040045import static org.slf4j.LoggerFactory.getLogger;
46
chengfanc58d4be2016-09-20 10:33:12 +080047
Henry Yue20926e2016-08-25 22:58:02 -040048/*
49 * This class is the main implementation of the RESTCONF Protocol
50 * Proxy module. Currently it only handles some basic operations
51 * on data resource nodes. However, the design intention is to
52 * create a code structure that allows new methods/functionality
53 * to be easily added in future releases.
54 */
55
56/**
57 * Implementation of the RESTCONF Protocol Proxy module.
58 */
59@Path("/")
60public class RestconfWebResource extends AbstractWebResource {
61
62 @Context
63 UriInfo uriInfo;
64
65 private final RestconfService service = get(RestconfService.class);
66 private final Logger log = getLogger(getClass());
67
68 /**
69 * Handles a RESTCONF GET operation against a target data resource. If the
70 * operation is successful, the JSON presentation of the resource plus HTTP
71 * status code "200 OK" is returned. Otherwise, HTTP error status code
72 * "400 Bad Request" is returned.
73 *
74 * @param uriString URI of the data resource.
75 * @return HTTP response
76 */
77 @GET
78 @Produces(MediaType.APPLICATION_JSON)
79 @Path("data/{identifier : .+}")
80 public Response handleGetRequest(@PathParam("identifier") String uriString) {
81
82 log.debug("handleGetRequest: {}", uriString);
83
84 try {
85 ObjectNode node = service.runGetOperationOnDataResource(uriString);
86 return ok(node).build();
87 } catch (RestconfException e) {
88 log.error("ERROR: handleGetRequest: {}", e.getMessage());
89 log.debug("Exception in handleGetRequest:", e);
90 return e.getResponse();
91 }
92 }
93
94 /**
95 * Handles the RESTCONF Event Notification Subscription request. If the
96 * subscription is successful, a ChunkedOutput stream is created and returned
97 * to the caller.
98 * <P></P>
99 * This function is not blocked on streaming the data (so that it can handle
100 * other incoming requests). Instead, a worker thread running in the background
101 * does the data streaming. If errors occur during streaming, the worker thread
102 * calls ChunkedOutput.close() to disconnect the session and terminates itself.
103 *
104 * @param streamId Event stream ID
105 * @return A string data stream over HTTP keep-alive session
106 */
107 @GET
108 @Produces(MediaType.APPLICATION_JSON)
109 @Path("streams/{streamId}")
110 public ChunkedOutput<String> handleNotificationRegistration(@PathParam("streamId") String streamId) {
111 final ChunkedOutput<String> output = new ChunkedOutput<String>(String.class);
112 try {
113 service.subscribeEventStream(streamId, output);
114 } catch (RestconfException e) {
115 log.error("ERROR: handleNotificationRegistration: {}", e.getMessage());
116 log.debug("Exception in handleNotificationRegistration:", e);
117 try {
118 output.close();
119 } catch (IOException ex) {
120 log.error("ERROR: handleNotificationRegistration:", ex);
121 }
122 }
123
124 return output;
125 }
126
127 /**
128 * Handles a RESTCONF POST operation against a data resource. If the
129 * operation is successful, HTTP status code "201 Created" is returned
130 * and there is no response message-body. If the data resource already
131 * exists, then the HTTP status code "409 Conflict" is returned.
132 *
133 * @param uriString URI of the data resource
134 * @param stream Input JSON object
135 * @return HTTP response
136 */
137 @POST
138 @Consumes(MediaType.APPLICATION_JSON)
139 @Produces(MediaType.APPLICATION_JSON)
140 @Path("data/{identifier : .+}")
chengfanc58d4be2016-09-20 10:33:12 +0800141 public Response handlePostRequest(@PathParam("identifier") String uriString,
142 InputStream stream) {
Henry Yue20926e2016-08-25 22:58:02 -0400143
144 log.debug("handlePostRequest: {}", uriString);
145
146 try {
147 ObjectNode rootNode = (ObjectNode) mapper().readTree(stream);
148
149 service.runPostOperationOnDataResource(uriString, rootNode);
150 return Response.created(uriInfo.getRequestUri()).build();
151 } catch (JsonProcessingException e) {
152 log.error("ERROR: handlePostRequest ", e);
chengfanc58d4be2016-09-20 10:33:12 +0800153 return Response.status(BAD_REQUEST).build();
Henry Yue20926e2016-08-25 22:58:02 -0400154 } catch (RestconfException e) {
155 log.error("ERROR: handlePostRequest: {}", e.getMessage());
156 log.debug("Exception in handlePostRequest:", e);
157 return e.getResponse();
158 } catch (IOException ex) {
159 log.error("ERROR: handlePostRequest ", ex);
chengfanc58d4be2016-09-20 10:33:12 +0800160 return Response.status(INTERNAL_SERVER_ERROR).build();
Henry Yue20926e2016-08-25 22:58:02 -0400161 }
162 }
163
164 /**
165 * Handles a RESTCONF PUT operation against a data resource. If a new
166 * resource is successfully created, then the HTTP status code "201 Created"
167 * is returned. If an existing resource is modified, then the HTTP
168 * status code "204 No Content" is returned. If the input JSON payload
169 * contains errors, then "400 Bad Request" is returned. If an exception
170 * occurs during the operation, the status code enclosed in
171 * the RestconfException object, such as "500 Internal Server Error",
172 * is returned.
173 *
174 * @param uriString URI of the data resource.
175 * @param stream Input JSON object
176 * @return HTTP response
177 */
178 @PUT
179 @Consumes(MediaType.APPLICATION_JSON)
180 @Produces(MediaType.APPLICATION_JSON)
181 @Path("data/{identifier : .+}")
chengfanc58d4be2016-09-20 10:33:12 +0800182 public Response handlePutRequest(@PathParam("identifier") String uriString,
183 InputStream stream) {
Henry Yue20926e2016-08-25 22:58:02 -0400184
185 log.debug("handlePutRequest: {}", uriString);
186
187 try {
188 ObjectNode rootNode = (ObjectNode) mapper().readTree(stream);
189
190 service.runPutOperationOnDataResource(uriString, rootNode);
191 return Response.created(uriInfo.getRequestUri()).build();
192 } catch (JsonProcessingException e) {
193 log.error("ERROR: handlePutRequest ", e);
chengfanc58d4be2016-09-20 10:33:12 +0800194 return Response.status(BAD_REQUEST).build();
Henry Yue20926e2016-08-25 22:58:02 -0400195 } catch (RestconfException e) {
196 log.error("ERROR: handlePutRequest: {}", e.getMessage());
197 log.debug("Exception in handlePutRequest:", e);
198 return e.getResponse();
199 } catch (IOException ex) {
200 log.error("ERROR: handlePutRequest ", ex);
chengfanc58d4be2016-09-20 10:33:12 +0800201 return Response.status(INTERNAL_SERVER_ERROR).build();
Henry Yue20926e2016-08-25 22:58:02 -0400202 }
203 }
204
205 /**
206 * Handles the RESTCONF DELETION Operation against a data resource. If the
207 * resource is successfully deleted, the HTTP status code "204 No Content"
208 * is returned in the response. If an exception occurs, then the
209 * HTTP status code enclosed in the RestconfException object is
210 * returned.
211 *
212 * @param uriString URI of the data resource to be deleted.
213 * @return HTTP response
214 */
215 @DELETE
216 @Produces(MediaType.APPLICATION_JSON)
217 @Path("data/{identifier : .+}")
218 public Response handleDeleteRequest(@PathParam("identifier") String uriString) {
219
220 log.debug("handleDeleteRequest: {}", uriString);
221
222 try {
223 service.runDeleteOperationOnDataResource(uriString);
224 return Response.ok().build();
225 } catch (RestconfException e) {
226 log.error("ERROR: handleDeleteRequest: {}", e.getMessage());
227 log.debug("Exception in handleDeleteRequest:", e);
228 return e.getResponse();
229 }
230 }
231
chengfanc58d4be2016-09-20 10:33:12 +0800232 /**
233 * Handles a RESTCONF PATCH operation against a data resource.
234 * If the PATCH request succeeds, a "200 OK" status-line is returned if
235 * there is a message-body, and "204 No Content" is returned if no
236 * response message-body is sent.
237 *
238 * @param uriString URI of the data resource
239 * @param stream Input JSON object
240 * @return HTTP response
241 */
242 @Patch
243 @Consumes(MediaType.APPLICATION_JSON)
244 @Produces(MediaType.APPLICATION_JSON)
245 @Path("data/{identifier : .+}")
246 public Response handlePatchRequest(@PathParam("identifier") String uriString,
247 InputStream stream) {
248
249 log.debug("handlePatchRequest: {}", uriString);
250
251 try {
252 ObjectNode rootNode = (ObjectNode) mapper().readTree(stream);
253
254 service.runPatchOperationOnDataResource(uriString, rootNode);
255 return Response.ok().build();
256 } catch (JsonProcessingException e) {
257 log.error("ERROR: handlePatchRequest ", e);
258 return Response.status(BAD_REQUEST).build();
259 } catch (RestconfException e) {
260 log.error("ERROR: handlePatchRequest: {}", e.getMessage());
261 log.debug("Exception in handlePatchRequest:", e);
262 return e.getResponse();
263 } catch (IOException ex) {
264 log.error("ERROR: handlePatchRequest ", ex);
265 return Response.status(INTERNAL_SERVER_ERROR).build();
266 }
267 }
268
Henry Yue20926e2016-08-25 22:58:02 -0400269}