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