HalDocsServlet.java
/*
* #%L
* wcm.io
* %%
* Copyright (C) 2015 wcm.io
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
package io.wcm.caravan.hal.docs.impl;
import java.io.IOException;
import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.CharEncoding;
import org.apache.commons.lang3.StringUtils;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.Service;
import org.osgi.framework.Bundle;
import org.osgi.service.component.ComponentContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import io.wcm.caravan.hal.docs.impl.model.LinkRelation;
import io.wcm.caravan.hal.docs.impl.reader.ServiceModelReader;
/**
* Serves HAL documentation pages generated from JSON service documentation models with handlebars.
*/
@Component(factory = HalDocsServlet.FACTORY)
@Service(Servlet.class)
public class HalDocsServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
static final String FACTORY = "caravan.haldocs.servlet.factory";
static final String PROPERTY_BUNDLE = "caravan.haldocs.relatedBundle";
private io.wcm.caravan.hal.docs.impl.model.Service serviceModel;
@Reference
private TemplateRenderer templateRenderer;
private static final Logger log = LoggerFactory.getLogger(HalDocsServlet.class);
@Activate
void activate(ComponentContext componentContext) {
// bundle which contains the JAX-RS services
Bundle bundle = (Bundle)componentContext.getProperties().get(PROPERTY_BUNDLE);
serviceModel = ServiceModelReader.read(bundle);
}
@Deactivate
void deactivate(ComponentContext componentContext) {
serviceModel = null;
}
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
HttpServletRequest request = (HttpServletRequest)servletRequest;
HttpServletResponse response = (HttpServletResponse)servletResponse;
if (serviceModel != null) {
try {
String uri = StringUtils.defaultString(request.getPathInfo());
if (StringUtils.equals(uri, "/")) {
sendMarkup(templateRenderer.renderServiceHtml(serviceModel), response);
return;
}
else {
String rel = StringUtils.substringAfter(uri, "/");
LinkRelation linkRelation = serviceModel.getLinkRelations().stream()
.filter(item -> StringUtils.equals(item.getRel(), rel))
.findFirst().orElse(null);
if (linkRelation != null) {
sendMarkup(templateRenderer.renderLinkRelationHtml(serviceModel, linkRelation), response);
return;
}
}
}
catch (Throwable ex) {
log.error("Error rendering HAL docs for " + serviceModel.getServiceId() + ": " + request.getPathInfo(), ex);
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, ex.getMessage());
}
}
response.sendError(HttpServletResponse.SC_NOT_FOUND);
}
private void sendMarkup(String markup, HttpServletResponse response) throws IOException {
byte[] data = markup.getBytes(CharEncoding.UTF_8);
response.setContentType(HttpContextWrapper.MIMETYPE_HTML);
response.setContentLength(data.length);
response.getOutputStream().write(data);
}
@Override
public void init() throws ServletException {
// nothing to do
}
@Override
public void init(ServletConfig config) throws ServletException {
// nothing to do
}
@Override
public void destroy() {
// nothing to do
}
}