1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.forgerock.json.resource.http.examples;
18
19 import static org.forgerock.http.handler.Handlers.chainOf;
20 import static org.forgerock.http.routing.RoutingMode.STARTS_WITH;
21 import static org.forgerock.json.resource.Applications.simpleCrestApplication;
22 import static org.forgerock.json.resource.Requests.newApiRequest;
23 import static org.forgerock.json.resource.Resources.newHandler;
24 import static org.forgerock.json.resource.Resources.newInternalConnectionFactory;
25 import static org.forgerock.json.resource.RouteMatchers.requestUriMatcher;
26 import static org.forgerock.json.resource.http.CrestHttp.newHttpHandler;
27
28 import io.swagger.v3.oas.models.OpenAPI;
29 import io.swagger.v3.oas.models.info.Info;
30 import org.asciidoctor.Asciidoctor;
31 import org.asciidoctor.Attributes;
32 import org.asciidoctor.Options;
33 import org.asciidoctor.Placement;
34 import org.asciidoctor.SafeMode;
35 import org.forgerock.api.markup.ApiDocGenerator;
36 import org.forgerock.api.models.ApiDescription;
37 import org.forgerock.http.ApiProducer;
38 import org.forgerock.http.DescribedHttpApplication;
39 import org.forgerock.http.Handler;
40 import org.forgerock.http.HttpApplicationException;
41 import org.forgerock.http.example.DescribedOauth2Endpoint;
42 import org.forgerock.http.header.ContentTypeHeader;
43 import org.forgerock.http.io.Buffer;
44 import org.forgerock.http.protocol.Request;
45 import org.forgerock.http.protocol.Response;
46 import org.forgerock.http.protocol.Status;
47 import org.forgerock.http.routing.RouteMatchers;
48 import org.forgerock.http.routing.RoutingMode;
49 import org.forgerock.http.swagger.OpenApiRequestFilter;
50 import org.forgerock.http.swagger.SwaggerApiProducer;
51 import org.forgerock.http.util.Uris;
52 import org.forgerock.json.resource.MemoryBackend;
53 import org.forgerock.json.resource.ResourcePath;
54 import org.forgerock.json.resource.Router;
55 import org.forgerock.json.resource.descriptor.examples.handler.UserCollectionHandler;
56 import org.forgerock.services.context.Context;
57 import org.forgerock.services.routing.DelegatingRouteMatcher;
58 import org.forgerock.services.routing.RouteMatch;
59 import org.forgerock.util.Factory;
60 import org.forgerock.util.promise.NeverThrowsException;
61 import org.forgerock.util.promise.Promise;
62
63
64
65
66 public class CrestHttpApplication implements DescribedHttpApplication {
67
68 private static final String SWAGGER_JSON_ROUTE = "../..?_api";
69
70 private static final ContentTypeHeader HTML_CONTENT_TYPE_HEADER =
71 ContentTypeHeader.valueOf("text/html; charset=UTF-8");
72
73 @Override
74 public Handler start() throws HttpApplicationException {
75 final Asciidoctor asciidoctor = Asciidoctor.Factory.create();
76
77 final Router crestRouter = new Router();
78 crestRouter.addRoute(requestUriMatcher(STARTS_WITH, "/users"), newHandler(new MemoryBackend()));
79 crestRouter.addRoute(requestUriMatcher(STARTS_WITH, "/groups"), newHandler(new MemoryBackend()));
80 crestRouter.addRoute(requestUriMatcher(STARTS_WITH, "/api/users"), UserCollectionHandler.getUsersRouter());
81 crestRouter.addRoute(requestUriMatcher(STARTS_WITH, "/api/admins"), UserCollectionHandler.getAdminsRouter());
82
83 Handler crestHandler = newHttpHandler(simpleCrestApplication(newInternalConnectionFactory(crestRouter),
84 "frapi:example", "1.0"));
85
86 final org.forgerock.http.routing.Router router = new org.forgerock.http.routing.Router();
87 router.setDefaultRoute(crestHandler);
88 router.addRoute(RouteMatchers.requestUriMatcher(RoutingMode.STARTS_WITH, "/chf/oauth2"),
89 new DescribedOauth2Endpoint());
90
91
92 router.addRoute(RouteMatchers.requestUriMatcher(RoutingMode.STARTS_WITH, "/docs/html"),
93 new Handler() {
94 @Override
95 public Promise<Response, NeverThrowsException> handle(Context context, Request request) {
96 ApiDescription apiDescription = crestRouter.handleApiRequest(context,
97 newApiRequest(ResourcePath.empty()));
98 final String asciiDocMarkup = ApiDocGenerator.execute("Users and Devices API", apiDescription,
99 null);
100
101 final String html;
102 synchronized (asciidoctor) {
103 html = asciidoctor.convert(asciiDocMarkup,
104 Options.builder()
105 .attributes(Attributes.builder()
106 .tableOfContents(Placement.LEFT)
107 .sectNumLevels(5)
108 .attribute("toclevels", 5)
109 .build())
110 .safe(SafeMode.SAFE)
111 .standalone(true)
112 .build());
113 }
114
115 final Response response = new Response(Status.OK);
116 response.getHeaders().add(HTML_CONTENT_TYPE_HEADER);
117 response.setEntity(html);
118 return Response.newResponsePromise(response);
119 }
120 });
121
122
123 router.addRoute(RouteMatchers.requestUriMatcher(RoutingMode.EQUALS, "/docs/api"),
124 new Handler() {
125 @Override
126 public Promise<Response, NeverThrowsException> handle(Context context, Request request) {
127 final String uri = request.getUri().toString();
128 final String baseUrl = uri.substring(0, uri.indexOf("/docs/api"));
129 final String url = baseUrl + "/openapi/index.html?url="
130 + Uris.urlEncodeQueryParameterNameOrValue(SWAGGER_JSON_ROUTE)
131 + "&title=" + Uris.urlEncodeQueryParameterNameOrValue("Users and Devices API");
132
133 final Response response = new Response(Status.FOUND);
134 response.getHeaders().add("Location", url);
135 return Response.newResponsePromise(response);
136 }
137 });
138
139
140 router.addRoute(new DelegatingRouteMatcher<Request>(RouteMatchers.requestUriMatcher(RoutingMode.EQUALS, "/")) {
141 @Override
142 public RouteMatch evaluate(Context context, Request request) {
143 if (request.getForm().containsKey("_crestapi")) {
144 return null;
145 }
146 return super.evaluate(context, request);
147 }
148 }, new Handler() {
149 @Override
150 public Promise<Response, NeverThrowsException> handle(Context context, Request request) {
151 final String html = "<!DOCTYPE html><html><head><title>CREST Examples</title></head><body>"
152 + "<p><a href=\"?_api\">Users and Devices API OpenAPI JSON</a></p>"
153 + "<p><a href=\"?_crestapi\">Users and Devices API CREST Descriptor JSON</a></p>"
154 + "<p><a href=\"./docs/api\">Users and Devices API explorer</a></p>"
155 + "<p><a href=\"./docs/html\">Users and Devices API documentation</a></p>"
156 + "</body></html>";
157
158 final Response response = new Response(Status.OK);
159 response.getHeaders().add(HTML_CONTENT_TYPE_HEADER);
160 response.setEntity(html);
161 return Response.newResponsePromise(response);
162 }
163 });
164 return chainOf(router, new OpenApiRequestFilter());
165 }
166
167 @Override
168 public Factory<Buffer> getBufferFactory() {
169 return null;
170 }
171
172 @Override
173 public void stop() {
174
175 }
176
177 @Override
178 public ApiProducer<OpenAPI> getApiProducer() {
179 return new SwaggerApiProducer(new Info().title("CREST Examples"), null, null);
180 }
181 }