001package org.javasimon.console.action; 002 003import org.javasimon.console.Action; 004import org.javasimon.console.ActionContext; 005import org.javasimon.console.ActionException; 006 007import java.io.IOException; 008import java.io.InputStream; 009import java.io.OutputStream; 010import java.util.HashMap; 011import java.util.Map; 012 013import javax.servlet.ServletException; 014import javax.servlet.http.HttpServletResponse; 015 016/** 017 * Action used to send resources (images, JS, CSS) to the browser. 018 * 019 * @author gquintana 020 */ 021public class ResourceAction extends Action { 022 023 public static final String PREFIX = "/resource"; 024 025 private static final Map<String, String> CONTENT_TYPES = new HashMap<>(); 026 027 static { 028 CONTENT_TYPES.put("gif", "image/gif"); 029 CONTENT_TYPES.put("png", "image/png"); 030 CONTENT_TYPES.put("jpg", "image/jpeg"); 031 CONTENT_TYPES.put("html", "text/html"); 032 CONTENT_TYPES.put("css", "text/css"); 033 CONTENT_TYPES.put("js", "text/javascript"); 034 } 035 036 /** 037 * Relative path of the resource to return. 038 */ 039 private final String resourcePath; 040 041 /** 042 * Constructor. 043 * 044 * @param context Action context 045 * @param resourcePath Local path of the resource 046 */ 047 public ResourceAction(ActionContext context, String resourcePath) { 048 super(context); 049 if (resourcePath.startsWith("/")) { 050 this.resourcePath = resourcePath; 051 } else { 052 this.resourcePath = "/" + resourcePath; 053 } 054 } 055 056 @Override 057 public void execute() throws ServletException, IOException, ActionException { 058 InputStream resourceIStream = null; 059 try { 060 resourceIStream = getClass().getResourceAsStream("/org/javasimon/console/resource" + resourcePath); 061 if (resourceIStream == null) { 062 getContext().getResponse().setStatus(HttpServletResponse.SC_NOT_FOUND); 063 throw new ActionException("Resource " + resourcePath + " not found"); 064 } 065 String extension = resourcePath.substring(resourcePath.lastIndexOf('.') + 1).toLowerCase(); 066 String contentType = CONTENT_TYPES.get(extension); 067 if (contentType != null) { 068 getContext().setContentType(contentType); 069 if (contentType.startsWith("text")) { 070 getContext().getResponse().setCharacterEncoding("UTF-8"); 071 } 072 } 073 getContext().getResponse().setHeader("Cache-Control", "public; max-age=300"); 074 copyStream(resourceIStream); 075 } finally { 076 if (resourceIStream != null) { 077 resourceIStream.close(); 078 } 079 } 080 } 081 082 /** 083 * Copy resource input stream to HTTP response output stream using 084 * a 64kib buffer 085 */ 086 private void copyStream(InputStream inputStream) throws IOException { 087 OutputStream outputStream = null; 088 try { 089 outputStream = getContext().getOutputStream(); 090 byte[] buffer = new byte[65535]; 091 int bufferLen; 092 int totalLen = 0; 093 while ((bufferLen = inputStream.read(buffer)) > 0) { 094 outputStream.write(buffer, 0, bufferLen); 095 totalLen += bufferLen; 096 } 097 getContext().getResponse().setContentLength(totalLen); 098 } finally { 099 if (outputStream != null) { 100 outputStream.flush(); 101 } 102 } 103 } 104}