blob: b9ee57b1025a3f30ce309c0dc6afe7a1e810e635 [file] [log] [blame]
Thomas Vachuska0fa2aa12015-08-18 12:53:04 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2015-present Open Networking Foundation
Thomas Vachuska0fa2aa12015-08-18 12:53:04 -07003 *
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
Thomas Vachuskaaf0ee532015-08-19 14:17:36 -0700114 public Response getDefault() throws IOException, URISyntaxException {
115 return uriInfo.getPath().endsWith("/") ? getIndex() :
116 temporaryRedirect(new URI(uriInfo.getPath() + "/")).build();
Thomas Vachuska0fa2aa12015-08-18 12:53:04 -0700117 }
118
119 /**
120 * Get Swagger UI main index page.
121 *
122 * @return 200 OK
Thomas Vachuska87ae1d92015-08-19 17:39:11 -0700123 * @throws IOException if unable to get index resource
Thomas Vachuska0fa2aa12015-08-18 12:53:04 -0700124 */
125 @GET
126 @Path("index.html")
127 public Response getIndex() throws IOException {
128 InputStream stream = getClass().getClassLoader().getResourceAsStream(DOCS + "index.html");
129 nullIsNotFound(stream, "index.html not found");
130
131 String index = new String(toByteArray(stream));
132
133 int p1s = split(index, 0, INJECT_START);
134 int p1e = split(index, p1s, INJECT_END);
135 int p2s = split(index, p1e, null);
136
137 StreamEnumeration streams =
138 new StreamEnumeration(of(stream(index, 0, p1s),
139 includeOptions(get(ApiDocService.class)),
140 stream(index, p1e, p2s)));
141
142 return ok(new SequenceInputStream(streams))
143 .header(CONTENT_TYPE, TEXT_HTML).build();
144 }
145
146 private InputStream includeOptions(ApiDocService service) {
147 StringBuilder sb = new StringBuilder();
148 service.getDocProviders().forEach(p -> {
149 sb.append("<option value=\"").append(p.key()).append("\"")
Jon Halla3fcf672017-03-28 16:53:22 -0700150 .append("/onos/v1".equals(p.key()) ? " selected>" : ">")
Thomas Vachuska0fa2aa12015-08-18 12:53:04 -0700151 .append(p.name())
152 .append("</option>");
153 });
154 return new ByteArrayInputStream(sb.toString().getBytes());
155 }
156
157 /**
158 * Get Swagger UI resource.
159 *
Thomas Vachuska87ae1d92015-08-19 17:39:11 -0700160 * @param resource path of the resource
Thomas Vachuska0fa2aa12015-08-18 12:53:04 -0700161 * @return 200 OK
Thomas Vachuska87ae1d92015-08-19 17:39:11 -0700162 * @throws IOException if unable to get named resource
Thomas Vachuska0fa2aa12015-08-18 12:53:04 -0700163 */
164 @GET
165 @Path("{resource: .*}")
166 public Response getResource(@PathParam("resource") String resource) throws IOException {
Jon Halla3fcf672017-03-28 16:53:22 -0700167 if ("".equals(resource)) {
Jian Li9d616492016-03-09 10:52:49 -0800168 return getIndex();
169 }
Thomas Vachuska0fa2aa12015-08-18 12:53:04 -0700170 InputStream stream = getClass().getClassLoader().getResourceAsStream(DOCS + resource);
171 return ok(nullIsNotFound(stream, resource + " not found"))
172 .header(CONTENT_TYPE, contentType(resource)).build();
173 }
174
175 static String contentType(String resource) {
176 return resource.endsWith(".html") ? TEXT_HTML :
177 resource.endsWith(".css") ? STYLESHEET :
178 resource.endsWith(".js") ? SCRIPT :
179 APPLICATION_OCTET_STREAM;
180 }
181}