Java tutorial
/* * Copyright 2014 Eko Khannedy * * 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.khannedy.sajikeun.servlet; import com.google.common.base.CharMatcher; import com.google.common.io.Resources; import com.google.common.net.HttpHeaders; import com.google.common.net.MediaType; import javax.servlet.ServletException; import javax.servlet.ServletOutputStream; 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.URISyntaxException; import java.nio.charset.Charset; import java.util.logging.Logger; import static com.google.common.base.Preconditions.checkArgument; /** * @author Eko Khannedy */ public class AssetServlet extends HttpServlet { private Logger logger = Logger.getLogger(AssetServlet.class.getName()); private static final CharMatcher SLASHES = CharMatcher.is('/'); private static final MediaType DEFAULT_MEDIA_TYPE = MediaType.HTML_UTF_8; private final File resourcePath; private final String uriPath; private final String indexFile; private final Charset defaultCharset; private final boolean cache; public AssetServlet(File resourcePath, String uriPath, String indexFile, Charset defaultCharset, boolean cache) { this.resourcePath = resourcePath; final String trimmedUri = SLASHES.trimTrailingFrom(uriPath); this.uriPath = trimmedUri.isEmpty() ? "/" : trimmedUri; this.indexFile = indexFile; this.defaultCharset = defaultCharset; this.cache = cache; } @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doHttp(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doHttp(req, resp); } protected void doHttp(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { try { final StringBuilder builder = new StringBuilder(req.getServletPath()); if (req.getPathInfo() != null) { builder.append(req.getPathInfo()); } final Asset asset = loadAsset(builder.toString()); if (asset == null) { resp.sendError(HttpServletResponse.SC_NOT_FOUND); return; } if (cache) { if (isCachedClientSide(req, asset)) { resp.sendError(HttpServletResponse.SC_NOT_MODIFIED); return; } } resp.setDateHeader(HttpHeaders.LAST_MODIFIED, asset.getLastModified()); resp.setHeader(HttpHeaders.ETAG, asset.getETag()); final String mimeTypeOfExtension = req.getServletContext().getMimeType(req.getRequestURI()); MediaType mediaType = DEFAULT_MEDIA_TYPE; if (mimeTypeOfExtension != null) { try { mediaType = MediaType.parse(mimeTypeOfExtension); if (defaultCharset != null && mediaType.is(MediaType.ANY_TEXT_TYPE)) { mediaType = mediaType.withCharset(defaultCharset); } } catch (IllegalArgumentException ignore) { } } resp.setContentType(mediaType.type() + '/' + mediaType.subtype()); if (mediaType.charset().isPresent()) { resp.setCharacterEncoding(mediaType.charset().get().toString()); } try (ServletOutputStream output = resp.getOutputStream()) { output.write(asset.getResource()); } } catch (RuntimeException | URISyntaxException ignored) { resp.sendError(HttpServletResponse.SC_NOT_FOUND); } } private Asset loadAsset(String key) throws URISyntaxException, IOException { checkArgument(key.startsWith(uriPath)); File file = new File(resourcePath, key); if (file.isDirectory()) { if (indexFile != null) { file = new File(file, indexFile); } else { // directory requested but no index file defined logger.info("[FAILED] " + file.getAbsolutePath()); return null; } } if (!file.exists()) { logger.info("[FAILED] " + file.getAbsolutePath()); return null; } logger.info("[SUCCESS] " + file.getAbsolutePath()); long lastModified = file.lastModified(); if (lastModified < 1) { // Something went wrong trying to get the last modified time: just use the current time lastModified = System.currentTimeMillis(); } // zero out the millis since the date we get back from If-Modified-Since will not have them lastModified = (lastModified / 1000) * 1000; return new Asset(Resources.toByteArray(file.toURI().toURL()), lastModified); } private boolean isCachedClientSide(HttpServletRequest req, Asset asset) { return asset.getETag().equals(req.getHeader(HttpHeaders.IF_NONE_MATCH)) || (req.getDateHeader(HttpHeaders.IF_MODIFIED_SINCE) >= asset.getLastModified()); } }