blob: c85e0b645c56f9cc0800881226f9bd0a651a2aa4 [file] [log] [blame]
Thomas Vachuska0fa2aa12015-08-18 12:53:04 -07001/*
2 * Copyright 2015 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 */
16package org.onosproject.rest.resources;
17
18import com.fasterxml.jackson.databind.node.ArrayNode;
19import com.fasterxml.jackson.databind.node.ObjectNode;
20import org.onosproject.rest.AbstractInjectionResource;
21import org.onosproject.rest.ApiDocService;
22
23import javax.ws.rs.GET;
24import javax.ws.rs.Path;
25import javax.ws.rs.PathParam;
Thomas Vachuskaaf0ee532015-08-19 14:17:36 -070026import javax.ws.rs.core.Context;
Thomas Vachuska0fa2aa12015-08-18 12:53:04 -070027import javax.ws.rs.core.Response;
Thomas Vachuskaaf0ee532015-08-19 14:17:36 -070028import javax.ws.rs.core.UriInfo;
Thomas Vachuska0fa2aa12015-08-18 12:53:04 -070029import java.io.ByteArrayInputStream;
30import java.io.IOException;
31import java.io.InputStream;
32import java.io.SequenceInputStream;
Thomas Vachuskaaf0ee532015-08-19 14:17:36 -070033import java.net.URI;
34import java.net.URISyntaxException;
Thomas Vachuska0fa2aa12015-08-18 12:53:04 -070035
36import static com.google.common.collect.ImmutableList.of;
37import static com.google.common.io.ByteStreams.toByteArray;
38import static javax.ws.rs.core.MediaType.*;
Thomas Vachuskaaf0ee532015-08-19 14:17:36 -070039import static javax.ws.rs.core.Response.temporaryRedirect;
Thomas Vachuska0fa2aa12015-08-18 12:53:04 -070040import static org.onlab.util.Tools.nullIsNotFound;
41
42/**
43 * REST API documentation.
44 */
45@Path("docs")
46public class ApiDocResource extends AbstractInjectionResource {
47
48 private static final String CONTENT_TYPE = "Content-Type";
49 private static final String STYLESHEET = "text/css";
50 private static final String SCRIPT = "text/javascript";
51 private static final String DOCS = "/docs/";
52
53 private static final String INJECT_START = "<!-- {API-START} -->";
54 private static final String INJECT_END = "<!-- {API-END} -->";
55
Thomas Vachuskaaf0ee532015-08-19 14:17:36 -070056 @Context
57 private UriInfo uriInfo;
58
Thomas Vachuska0fa2aa12015-08-18 12:53:04 -070059 /**
60 * Get all registered REST API docs.
61 * Returns array of all registered API docs.
62 *
63 * @return 200 OK
64 */
65 @GET
66 @Path("apis")
67 public Response getApiList() {
68 ObjectNode root = mapper().createObjectNode();
69 ArrayNode apis = newArray(root, "apis");
70 get(ApiDocService.class).getDocProviders().forEach(p -> apis.add(p.name()));
71 return ok(root.toString()).build();
72 }
73
74 /**
75 * Get Swagger UI JSON.
76 *
77 * @param key REST API web context
78 * @return 200 OK
79 */
80 @GET
81 @Path("apis/{key: .*?}/swagger.json")
82 public Response getApi(@PathParam("key") String key) {
83 String k = key.startsWith("/") ? key : "/" + key;
84 InputStream stream = nullIsNotFound(get(ApiDocService.class).getDocProvider(k),
85 "REST API not found for " + k).docs();
86 return ok(nullIsNotFound(stream, "REST API docs not found for " + k))
87 .header(CONTENT_TYPE, APPLICATION_JSON).build();
88 }
89
90 /**
91 * Get REST API model schema.
92 *
93 * @param key REST API web context
94 * @return 200 OK
95 */
96 @GET
97 @Path("apis/{key: .*?}/model.json")
98 public Response getApiModel(@PathParam("name") String key) {
99 String k = key.startsWith("/") ? key : "/" + key;
100 InputStream stream = nullIsNotFound(get(ApiDocService.class).getDocProvider(k),
101 "REST API not found for " + k).model();
102 return ok(nullIsNotFound(stream, "REST API model not found for " + k))
103 .header(CONTENT_TYPE, APPLICATION_JSON).build();
104 }
105
106 /**
107 * Get Swagger UI main index page.
108 *
109 * @return 200 OK
Thomas Vachuska87ae1d92015-08-19 17:39:11 -0700110 * @throws IOException if unable to get index resource
111 * @throws URISyntaxException if unable to create redirect URI
Thomas Vachuska0fa2aa12015-08-18 12:53:04 -0700112 */
113 @GET
114 @Path("/")
Thomas Vachuskaaf0ee532015-08-19 14:17:36 -0700115 public Response getDefault() throws IOException, URISyntaxException {
116 return uriInfo.getPath().endsWith("/") ? getIndex() :
117 temporaryRedirect(new URI(uriInfo.getPath() + "/")).build();
Thomas Vachuska0fa2aa12015-08-18 12:53:04 -0700118 }
119
120 /**
121 * Get Swagger UI main index page.
122 *
123 * @return 200 OK
Thomas Vachuska87ae1d92015-08-19 17:39:11 -0700124 * @throws IOException if unable to get index resource
Thomas Vachuska0fa2aa12015-08-18 12:53:04 -0700125 */
126 @GET
127 @Path("index.html")
128 public Response getIndex() throws IOException {
129 InputStream stream = getClass().getClassLoader().getResourceAsStream(DOCS + "index.html");
130 nullIsNotFound(stream, "index.html not found");
131
132 String index = new String(toByteArray(stream));
133
134 int p1s = split(index, 0, INJECT_START);
135 int p1e = split(index, p1s, INJECT_END);
136 int p2s = split(index, p1e, null);
137
138 StreamEnumeration streams =
139 new StreamEnumeration(of(stream(index, 0, p1s),
140 includeOptions(get(ApiDocService.class)),
141 stream(index, p1e, p2s)));
142
143 return ok(new SequenceInputStream(streams))
144 .header(CONTENT_TYPE, TEXT_HTML).build();
145 }
146
147 private InputStream includeOptions(ApiDocService service) {
148 StringBuilder sb = new StringBuilder();
149 service.getDocProviders().forEach(p -> {
150 sb.append("<option value=\"").append(p.key()).append("\"")
151 .append(p.key().equals("/onos/v1") ? " selected>" : ">")
152 .append(p.name())
153 .append("</option>");
154 });
155 return new ByteArrayInputStream(sb.toString().getBytes());
156 }
157
158 /**
159 * Get Swagger UI resource.
160 *
Thomas Vachuska87ae1d92015-08-19 17:39:11 -0700161 * @param resource path of the resource
Thomas Vachuska0fa2aa12015-08-18 12:53:04 -0700162 * @return 200 OK
Thomas Vachuska87ae1d92015-08-19 17:39:11 -0700163 * @throws IOException if unable to get named resource
Thomas Vachuska0fa2aa12015-08-18 12:53:04 -0700164 */
165 @GET
166 @Path("{resource: .*}")
167 public Response getResource(@PathParam("resource") String resource) throws IOException {
Jian Li9d616492016-03-09 10:52:49 -0800168 if (resource != null && resource.equals("")) {
169 return getIndex();
170 }
Thomas Vachuska0fa2aa12015-08-18 12:53:04 -0700171 InputStream stream = getClass().getClassLoader().getResourceAsStream(DOCS + resource);
172 return ok(nullIsNotFound(stream, resource + " not found"))
173 .header(CONTENT_TYPE, contentType(resource)).build();
174 }
175
176 static String contentType(String resource) {
177 return resource.endsWith(".html") ? TEXT_HTML :
178 resource.endsWith(".css") ? STYLESHEET :
179 resource.endsWith(".js") ? SCRIPT :
180 APPLICATION_OCTET_STREAM;
181 }
182}