/* This file is part of Cyclos (www.cyclos.org). A project of the Social Trade Organisation (www.socialtrade.org). Cyclos is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Cyclos is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Cyclos; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package nl.strohalm.cyclos.utils; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Collection; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import nl.strohalm.cyclos.entities.Entity; import nl.strohalm.cyclos.entities.groups.Group; import nl.strohalm.cyclos.entities.groups.GroupFilter; import nl.strohalm.cyclos.services.settings.SettingsService; import nl.strohalm.cyclos.utils.validation.ValidationError; import nl.strohalm.cyclos.utils.validation.ValidationException; import org.apache.commons.io.IOUtils; import org.apache.commons.lang.StringUtils; /** * Helper class for working with the response object * @author luis */ public class ResponseHelper { public static enum Status { SUCCESS, ERROR; @Override public String toString() { return super.toString().toLowerCase(); } } private MessageHelper messageHelper; private SettingsService settingsService; /** * Adds a cookie with the given name and value set for the context path root */ public Cookie addRootCookie(final HttpServletRequest request, final HttpServletResponse response, final String name, final Object value) { final Cookie cookie = new Cookie(name, value == null ? "" : value.toString()); cookie.setPath(request.getContextPath()); response.addCookie(cookie); return cookie; } /** * Set the specified response as a file download (attachment) */ public void setDownload(final HttpServletResponse response, final String fileName) { response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\";"); // In order for IE to find the download, we must remove the cache headers >:-( response.setHeader("Pragma", "Public"); response.setHeader("Cache-Control", ""); } /** * Set the correct character encoding (according to the settings) */ public void setEncoding(final HttpServletResponse response) { response.setCharacterEncoding(settingsService.getLocalSettings().getCharset()); } /** * Set the specified response to open inline (no attachment) */ public void setInline(final HttpServletResponse response) { response.setHeader("Content-Disposition", "inline"); } /** * Sets the cookies for the guest pages, based on the given group / group filter */ public void setLoginCookies(final HttpServletRequest request, final HttpServletResponse response, final Entity entity) { Long groupId = null; Long groupFilterId = null; if (entity instanceof Group) { groupId = entity.getId(); } else if (entity instanceof GroupFilter) { groupFilterId = entity.getId(); } addRootCookie(request, response, "groupId", groupId); addRootCookie(request, response, "groupFilterId", groupFilterId); } public void setMessageHelper(final MessageHelper messageHelper) { this.messageHelper = messageHelper; } /** * Set the response header to use no cache */ public void setNoCache(final HttpServletResponse response) { response.setHeader("Pragma", "No-cache"); response.setHeader("Cache-Control", "must-revalidate,no-cache,no-store,max-age=0"); response.setDateHeader("Expires", 1); } public void setSettingsService(final SettingsService settingsService) { this.settingsService = settingsService; } /** * Set the response as text/plain, with the correct character encoding (according to the settings) and no cache */ public void setTextNoCache(final HttpServletResponse response) { response.setContentType("text/plain"); setEncoding(response); setNoCache(response); } /** * Set the response as text/xml, with the correct character encoding (according to the settings) and no cache */ public void setXmlNoCache(final HttpServletResponse response) { response.setContentType("text/xml"); setEncoding(response); setNoCache(response); } /** * Writes a file contents to the response */ public void writeFile(final HttpServletResponse response, final File file) throws IOException { if (file.exists()) { response.setContentLength((int) file.length()); response.setDateHeader("Last-Modified", file.lastModified()); final InputStream in = new FileInputStream(file); try { IOUtils.copy(in, response.getOutputStream()); } finally { IOUtils.closeQuietly(in); } } } /** * Writes a JSON response */ public void writeJSON(final HttpServletResponse response, final JSONBuilder json) { try { final PrintWriter out = response.getWriter(); out.print("{\"result\":"); json.write(out); out.print("}"); } catch (final Exception e) { throw new IllegalStateException("Error writing JSON string", e); } } /** * Writes a JSON response */ public void writeJSON(final HttpServletResponse response, final String json) { try { response.getWriter().print("{\"result\":" + json + "}"); } catch (final Exception e) { throw new IllegalStateException("Error writing JSON string", e); } } /** * Write the status to the response as XML */ public void writeStatus(final HttpServletResponse response, final Object status, final Map<String, ?> fields) { final StringBuilder sb = new StringBuilder(); sb.append("<?xml version='1.0' encoding='").append(settingsService.getLocalSettings().getCharset()).append("'?>"); sb.append("<status value='").append(status).append("'>"); if (fields != null && !fields.isEmpty()) { for (final Map.Entry<String, ?> entry : fields.entrySet()) { final String tag = entry.getKey(); sb.append('<').append(tag).append("><![CDATA["); sb.append(entry.getValue()); sb.append("]]></").append(tag).append('>'); } } sb.append("</status>"); setXmlNoCache(response); try { response.getWriter().print(sb.toString()); } catch (final IOException e1) { throw new IllegalStateException("Error writing status xml: " + e1); } } /** * Write the validation errors if there are any. When no errors are found, the response body will be empty. */ public void writeValidationErrors(final HttpServletResponse response, final ValidationException e) { final Map<String, Object> fields = new LinkedHashMap<String, Object>(); final StringBuilder sb = new StringBuilder(); if (e.hasErrors()) { for (final ValidationError error : e.getGeneralErrors()) { sb.append(messageHelper.message(error.getKey(), error.getArguments())).append('\n'); } for (final Map.Entry<String, Collection<ValidationError>> entry : e.getErrorsByProperty().entrySet()) { final String property = entry.getKey(); final String key = e.getPropertyKey(property); final String displayName = e.getPropertyDisplayName(property); String propertyMessage = property; if (key != null) { propertyMessage = messageHelper.message(key); } else if (displayName != null) { propertyMessage = displayName; } for (final ValidationError error : entry.getValue()) { final List<Object> args = new ArrayList<Object>(); args.add(propertyMessage); if (error.getArguments() != null) { args.addAll(error.getArguments()); } sb.append(messageHelper.message(error.getKey(), args.toArray())).append('\n'); } } } else { sb.append(messageHelper.message("error.validation")); } fields.put("message", sb.toString()); fields.put("properties", StringUtils.join(e.getErrorsByProperty().keySet().iterator(), ',')); writeStatus(response, Status.ERROR, fields); } /** * Used when no validation error occured */ public void writeValidationSuccess(final HttpServletResponse response) { writeStatus(response, Status.SUCCESS, null); } }