package com.elibom.jogger.http.servlet; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.Closeable; import java.io.IOException; import java.util.HashMap; import java.util.Map; import javax.servlet.http.HttpServletResponse; import com.elibom.jogger.asset.Asset; import com.elibom.jogger.http.Cookie; import com.elibom.jogger.http.HttpException; import com.elibom.jogger.http.Response; import com.elibom.jogger.template.TemplateEngine; import com.elibom.jogger.template.TemplateException; import com.elibom.jogger.util.Preconditions; /** * A {@link Response} implementation based on the Servlet API. * * @author German Escobar */ public class ServletResponse implements Response { /** * The underlying Servlet Response. */ private HttpServletResponse response; private TemplateEngine templateEngine; /** * The attributes that we are passing to the view. */ private Map<String,Object> attributes = new HashMap<String,Object>(); private boolean written = false; /** * Constructor. Initializes the object with the underlying Servlet Response and the FreeMarker configuration. * * @param response the Servlet response object. * @param templateEngine the {@link TemplateEngine} implementation to use. */ public ServletResponse(HttpServletResponse response, TemplateEngine templateEngine) { Preconditions.notNull(response, "no response provided."); Preconditions.notNull(templateEngine, "no templateEngine provided."); this.response = response; response.setStatus(Response.NOT_FOUND); this.templateEngine = templateEngine; } @Override public int getStatus() { return response.getStatus(); } @Override public Response status(int status) { response.setStatus(status); return this; } @Override public Response badRequest() { response.setStatus(Response.BAD_REQUEST); return this; } @Override public Response unauthorized() { response.setStatus(Response.UNAUTHORIZED); return this; } @Override public Response notFound() { response.setStatus(Response.NOT_FOUND); return this; } @Override public Response conflict() { response.setStatus(Response.CONFLICT); return this; } @Override public String getContentType() { return response.getContentType(); } @Override public Response contentType(String contentType) { response.setContentType(contentType); return this; } @Override public String getHeader(String name) { return response.getHeader(name); } @Override public Response setHeader(String name, String value) { response.setHeader(name, value); return this; } @Override public Response setCookie(Cookie cookie) { response.addCookie(map(cookie)); return this; } @Override public Response removeCookie(Cookie cookie) { cookie.setMaxAge(0); setCookie(cookie); return this; } javax.servlet.http.Cookie map(Cookie cookie) { javax.servlet.http.Cookie servletCookie = new javax.servlet.http.Cookie(cookie.getName(), cookie.getValue()); servletCookie.setMaxAge(cookie.getMaxAge()); if (cookie.getPath() != null) { servletCookie.setPath(cookie.getPath()); } if (cookie.getDomain() != null) { servletCookie.setDomain(cookie.getDomain()); } servletCookie.setHttpOnly(cookie.isHttpOnly()); servletCookie.setSecure(cookie.isSecure()); return servletCookie; } @Override public Map<String, Object> getAttributes() { return attributes; } @Override public Response setAttribute(String name, Object object) { Preconditions.notEmpty(name, "no name provided."); Preconditions.notNull(object, "no object specified"); attributes.put(name, object); return this; } @Override public Response write(String html) throws HttpException { try { response.getWriter().print(html); this.written = true; return this; } catch (IOException e) { throw new HttpException(e); } } @Override public Response write(Asset asset) { response.setBufferSize(10240); response.setContentType(asset.getContentType()); response.setHeader("Content-Length", String.valueOf(asset.getLength())); String contentDisposition = response.getHeader("Content-Disposition"); if (contentDisposition == null || "".equals(contentDisposition.trim())) { response.setHeader("Content-Disposition", "inline; filename=\"" + asset.getName() + "\""); } // prepare streams BufferedInputStream input = null; BufferedOutputStream output = null; try { // open streams input = new BufferedInputStream(asset.getInputStream(), 10240); output = new BufferedOutputStream(response.getOutputStream(), 10240); // Write file contents to response. byte[] buffer = new byte[10240]; int length; while ((length = input.read(buffer)) > 0) { this.written = true; output.write(buffer, 0, length); } } catch (IOException e) { throw new HttpException(e); } finally { close(output); close(input); } return this; } private static void close(Closeable resource) { if (resource != null) { try { resource.close(); } catch (IOException e) {} } } @Override public Response render(String templateName) throws TemplateException { return render(templateName, new HashMap<String,Object>()); } @Override public Response render(String templateName, Map<String, Object> atts) throws TemplateException { // merge the user attributes with the controller attributes attributes.putAll(atts); try { templateEngine.render(templateName, attributes, response.getWriter()); this.written = true; } catch (IOException e) { throw new TemplateException(e); } return this; } @Override public void redirect(String path) throws HttpException { try { response.sendRedirect(path); } catch (IOException e) { throw new HttpException(e); } } @Override public boolean isWritten() { return written; } }