View Javadoc
1   /*
2    * #%L
3    * wcm.io
4    * %%
5    * Copyright (C) 2015 wcm.io
6    * %%
7    * Licensed under the Apache License, Version 2.0 (the "License");
8    * you may not use this file except in compliance with the License.
9    * You may obtain a copy of the License at
10   *
11   *      http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing, software
14   * distributed under the License is distributed on an "AS IS" BASIS,
15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   * See the License for the specific language governing permissions and
17   * limitations under the License.
18   * #L%
19   */
20  package io.wcm.caravan.hal.docs.impl;
21  
22  import java.io.IOException;
23  
24  import javax.servlet.Servlet;
25  import javax.servlet.ServletConfig;
26  import javax.servlet.ServletException;
27  import javax.servlet.ServletRequest;
28  import javax.servlet.ServletResponse;
29  import javax.servlet.http.HttpServlet;
30  import javax.servlet.http.HttpServletRequest;
31  import javax.servlet.http.HttpServletResponse;
32  
33  import org.apache.commons.lang3.CharEncoding;
34  import org.apache.commons.lang3.StringUtils;
35  import org.apache.felix.scr.annotations.Activate;
36  import org.apache.felix.scr.annotations.Component;
37  import org.apache.felix.scr.annotations.Deactivate;
38  import org.apache.felix.scr.annotations.Reference;
39  import org.apache.felix.scr.annotations.Service;
40  import org.osgi.framework.Bundle;
41  import org.osgi.service.component.ComponentContext;
42  import org.slf4j.Logger;
43  import org.slf4j.LoggerFactory;
44  
45  import io.wcm.caravan.hal.docs.impl.model.LinkRelation;
46  import io.wcm.caravan.hal.docs.impl.reader.ServiceModelReader;
47  
48  /**
49   * Serves HAL documentation pages generated from JSON service documentation models with handlebars.
50   */
51  @Component(factory = HalDocsServlet.FACTORY)
52  @Service(Servlet.class)
53  public class HalDocsServlet extends HttpServlet {
54  
55    private static final long serialVersionUID = 1L;
56  
57    static final String FACTORY = "caravan.haldocs.servlet.factory";
58    static final String PROPERTY_BUNDLE = "caravan.haldocs.relatedBundle";
59  
60    private io.wcm.caravan.hal.docs.impl.model.Service serviceModel;
61  
62    @Reference
63    private TemplateRenderer templateRenderer;
64  
65    private static final Logger log = LoggerFactory.getLogger(HalDocsServlet.class);
66  
67    @Activate
68    void activate(ComponentContext componentContext) {
69      // bundle which contains the JAX-RS services
70      Bundle bundle = (Bundle)componentContext.getProperties().get(PROPERTY_BUNDLE);
71      serviceModel = ServiceModelReader.read(bundle);
72    }
73  
74    @Deactivate
75    void deactivate(ComponentContext componentContext) {
76      serviceModel = null;
77    }
78  
79    @Override
80    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
81      HttpServletRequest request = (HttpServletRequest)servletRequest;
82      HttpServletResponse response = (HttpServletResponse)servletResponse;
83  
84      if (serviceModel != null) {
85        try {
86          String uri = StringUtils.defaultString(request.getPathInfo());
87          if (StringUtils.equals(uri, "/")) {
88            sendMarkup(templateRenderer.renderServiceHtml(serviceModel), response);
89            return;
90          }
91          else {
92            String rel = StringUtils.substringAfter(uri, "/");
93            LinkRelation linkRelation = serviceModel.getLinkRelations().stream()
94                .filter(item -> StringUtils.equals(item.getRel(), rel))
95                .findFirst().orElse(null);
96            if (linkRelation != null) {
97              sendMarkup(templateRenderer.renderLinkRelationHtml(serviceModel, linkRelation), response);
98              return;
99            }
100         }
101       }
102       catch (Throwable ex) {
103         log.error("Error rendering HAL docs for " + serviceModel.getServiceId() + ": " + request.getPathInfo(), ex);
104         response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, ex.getMessage());
105       }
106     }
107 
108     response.sendError(HttpServletResponse.SC_NOT_FOUND);
109   }
110 
111   private void sendMarkup(String markup, HttpServletResponse response) throws IOException {
112     byte[] data = markup.getBytes(CharEncoding.UTF_8);
113     response.setContentType(HttpContextWrapper.MIMETYPE_HTML);
114     response.setContentLength(data.length);
115     response.getOutputStream().write(data);
116   }
117 
118   @Override
119   public void init() throws ServletException {
120     // nothing to do
121   }
122 
123   @Override
124   public void init(ServletConfig config) throws ServletException {
125     // nothing to do
126   }
127 
128   @Override
129   public void destroy() {
130     // nothing to do
131   }
132 
133 }