com.ovea.markup.web.MarkupServlet Maven / Gradle / Ivy
/**
* Copyright (C) 2011 Ovea
*
* 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.
*/
package com.ovea.markup.web;
import com.ovea.markup.MarkupAttributes;
import com.ovea.markup.Template;
import com.ovea.markup.TemplateRegistry;
import com.ovea.markup.util.ExceptionUtil;
import com.ovea.markup.util.Gzip;
import com.ovea.markup.util.MimeTypes;
import com.ovea.markup.util.Resource;
import javax.inject.Inject;
import javax.inject.Provider;
import javax.inject.Singleton;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
@Singleton
public class MarkupServlet extends HttpServlet {
private static Logger LOGGER = Logger.getLogger(MarkupServlet.class.getName());
private static final long serialVersionUID = -9052484265570140129L;
private String charset = "UTF-8";
private boolean debug;
private File webappDir;
private List supportedMarkups = Arrays.asList("html");
private TemplateRegistry registry;
private Provider markupAttributes = new Provider() {
@Override
public MarkupAttributes get() {
return new MarkupAttributes();
}
};
private Provider locale = new Provider() {
@Override
public Locale get() {
throw new UnsupportedOperationException();
}
};
public String getCharset(String path) {
return charset;
}
public void setCharset(String charset) {
this.charset = charset;
}
public boolean isDebug() {
return debug;
}
public void setDebug(boolean debug) {
this.debug = debug;
}
@Inject
public void setLocale(Provider locale) {
this.locale = locale;
}
@Inject
public void setMarkupAttributes(Provider markupAttributes) {
this.markupAttributes = markupAttributes;
}
@Inject
public void setTemplateRegistry(TemplateRegistry registry) {
this.registry = registry;
}
public void setSupportedMarkups(List supportedMarkups) {
this.supportedMarkups = supportedMarkups;
}
public Locale getCurrentLocale() {
return locale.get();
}
public MarkupAttributes getCurrentMarkupAttributes() {
return markupAttributes.get();
}
public TemplateRegistry getTemplateRegistry() {
return registry;
}
public List getSupportedMarkups() {
return supportedMarkups;
}
public File getWebappDir() {
return webappDir;
}
@Override
public void init(ServletConfig config) throws ServletException {
super.init(config);
String debug = config.getInitParameter("debug");
if(debug != null)
setDebug(Boolean.valueOf(debug));
try {
webappDir = new File(config.getServletContext().getRealPath("")).getCanonicalFile();
} catch (IOException e) {
throw new ServletException(e.getMessage(), e);
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
List exts = getSupportedMarkups();
String path = request.getRequestURI();
if (path.startsWith(request.getContextPath()))
path = path.substring(request.getContextPath().length());
if (path != null) {
int pos = path.lastIndexOf('.');
if (pos != -1) {
path = path.toLowerCase();
int end = path.indexOf(";jsessionid", pos);
if (end != -1)
path = path.substring(0, end);
pos = exts.indexOf(path.substring(pos + 1));
if (pos != -1) {
response.setHeader("Cache-Control", "no-store, no-cache, must-revalidate, max-age=0");
response.setHeader("Pragma", "no-cache");
try {
Template template = resolveTemplate(path);
String markup = template.merge(buildAttributes(request, response, path));
String charset = getCharset(path);
byte[] data = markup.getBytes(charset);
response.setContentType(MimeTypes.getContentTypeForExtension(exts.get(pos)));
response.setCharacterEncoding(charset);
byte[] compressed = Gzip.compress(data);
response.setHeader("Content-Encoding", "gzip");
response.setContentLength(compressed.length);
response.getOutputStream().write(compressed);
response.setStatus(HttpServletResponse.SC_OK);
} catch (IllegalArgumentException e) {
if (isDebug())
response.sendError(HttpServletResponse.SC_NOT_FOUND, ExceptionUtil.getStackTrace(e));
else
response.sendError(HttpServletResponse.SC_NOT_FOUND);
LOGGER.log(Level.SEVERE, "Error serving markup " + path + " : " + e.getMessage(), e);
} catch (Exception e) {
if (isDebug())
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, ExceptionUtil.getStackTrace(e));
else
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
LOGGER.log(Level.SEVERE, "Error serving markup " + path + " : " + e.getMessage(), e);
}
return;
}
}
}
response.sendError(HttpServletResponse.SC_NOT_FOUND);
}
/**
* The artifact is a path info from a web request. PathInfo DOC, copied from {@link javax.servlet.http.HttpServletRequest#getPathInfo()}
*
* Returns any extra path information associated with
* the URL the client sent when it made this request.
* The extra path information follows the servlet path
* but precedes the query string and will start with
* a "/" character.
*
* This method returns null
if there
* was no extra path information.
*
* Same as the value of the CGI variable PATH_INFO.
*
* @return a String
, decoded by the
* web container, specifying
* extra path information that comes
* after the servlet path but before
* the query string in the request URL;
* or null
if the URL does not have
* any extra path information
*/
protected Template resolveTemplate(String artifact) throws IllegalArgumentException {
artifact = artifact.toLowerCase();
StringBuilder templateName = new StringBuilder(artifact);
if (templateName.charAt(0) == '/')
templateName.deleteCharAt(0);
File asked;
try {
asked = new File(getWebappDir(), templateName.toString()).getCanonicalFile();
} catch (IOException e) {
throw new IllegalArgumentException(e.getMessage(), e);
}
if (!asked.getAbsolutePath().startsWith(getWebappDir().getAbsolutePath()))
throw new IllegalArgumentException("Web template folder " + getWebappDir() + " cannot serve asked template " + artifact);
try {
return getTemplateRegistry().getTemplate(Resource.from(asked.toURI().toURL()));
} catch (MalformedURLException e) {
throw new IllegalArgumentException(e.getMessage(), e);
}
}
protected Map buildAttributes(final HttpServletRequest request, HttpServletResponse response, String path) {
MarkupAttributes attributes = getCurrentMarkupAttributes();
Map requestAttributes = new LinkedHashMap();
Enumeration keys = request.getAttributeNames();
while (keys.hasMoreElements()) {
String key = keys.nextElement();
requestAttributes.put(key, request.getAttribute(key));
}
Map requestParameters = new LinkedHashMap();
keys = request.getParameterNames();
while (keys.hasMoreElements()) {
String key = keys.nextElement();
requestParameters.put(key, request.getParameter(key));
}
attributes.set("param", requestParameters);
attributes.set("attr", requestAttributes);
attributes.set("locale", locale.get().toString());
attributes.set("request", request);
attributes.set("response", response);
return attributes.asMap();
}
}