001/* 002 * (C) Copyright 2015 Nuxeo SA (http://nuxeo.com/) and contributors. 003 * 004 * All rights reserved. This program and the accompanying materials 005 * are made available under the terms of the GNU Lesser General Public License 006 * (LGPL) version 2.1 which accompanies this distribution, and is available at 007 * http://www.gnu.org/licenses/lgpl-2.1.html 008 * 009 * This library is distributed in the hope that it will be useful, 010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 012 * Lesser General Public License for more details. 013 * 014 * Contributors: 015 * thibaud 016 */ 017package org.nuxeo.diff.pictures; 018 019import java.io.IOException; 020import java.io.InputStream; 021import java.io.OutputStream; 022import java.io.Serializable; 023import java.util.HashMap; 024 025import javax.servlet.ServletException; 026import javax.servlet.http.HttpServlet; 027import javax.servlet.http.HttpServletRequest; 028import javax.servlet.http.HttpServletResponse; 029 030import org.apache.commons.lang.StringUtils; 031import org.apache.commons.logging.Log; 032import org.apache.commons.logging.LogFactory; 033import org.nuxeo.ecm.core.api.Blob; 034import org.nuxeo.ecm.core.api.CoreInstance; 035import org.nuxeo.ecm.core.api.CoreSession; 036import org.nuxeo.ecm.core.api.DocumentModel; 037import org.nuxeo.ecm.core.api.IdRef; 038import org.nuxeo.ecm.core.api.repository.RepositoryManager; 039import org.nuxeo.ecm.platform.commandline.executor.api.CommandNotAvailable; 040import org.nuxeo.ecm.platform.web.common.ServletHelper; 041import org.nuxeo.runtime.api.Framework; 042 043/** 044 * /nuxeo/diffPictures?&repo=therepo&leftDocId=123456&rightDocId= 456789012 045 * &xpath=file:content&commandLine=thecommandline&fuzz=1000&highlightColor=Red &lowlightColor=White&altExtension=jpg 046 * <p> 047 * <ul> 048 * <li><code>leftDocId</code> and <code>rightDocId</code> are required</li> 049 * <li>All other parameters are optional (commandLine, xpath, fuzz, ...). Default values are defined in 050 * <code>DiffPictures</code></li> 051 * <li><code>altExtension</code> is special. If the pictures to compare are _not_ jpeg, png, or gif, _and_ if this 052 * parameter is set, then the result picture will be of this kind. Useful when comparing 2 psd or tif files for example, 053 * and the browser can't display them</li> 054 * </ul> 055 * <p> 056 * commandline, xpath, fuzz, highlightColor, lowlightColor and repo are optional Utility to force cleanup of temporary 057 * files created on the server: /nuxeo/diffPictures?cleanup=true&leftDocId=123456&rightDocId=456789& WARNING: Why can't 058 * I use the public static void downloadBlob() from DownloadServlet? 059 * 060 * @since 7.4 061 */ 062public class DiffPicturesServlet extends HttpServlet { 063 064 private static final long serialVersionUID = 1L; 065 066 private static final Log log = LogFactory.getLog(DiffPicturesServlet.class); 067 068 protected static final int BUFFER_SIZE = 1024 * 512; 069 070 @Override 071 protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 072 073 DocumentModel leftDoc, rightDoc; 074 075 String leftDocId = req.getParameter("leftDocId"); 076 String rightDocId = req.getParameter("rightDocId"); 077 078 if (StringUtils.isBlank(leftDocId)) { 079 sendTextResponse(resp, "you must specify a left document as origin"); 080 return; 081 } 082 if (StringUtils.isBlank(rightDocId)) { 083 sendTextResponse(resp, "you must specify 'right' used for comparison against the left document."); 084 return; 085 } 086 087 // WARNING: If you change the name of a parameter, also change it in nuxeo-diff-pictures.js 088 String repo = req.getParameter("repo"); 089 String xpath = req.getParameter("xpath"); 090 String commandLine = req.getParameter("commandLine"); 091 String fuzz = req.getParameter("fuzz"); 092 String highlightColor = req.getParameter("highlightColor"); 093 String lowlightColor = req.getParameter("lowlightColor"); 094 String altExtension = req.getParameter("altExtension"); 095 096 if (StringUtils.isBlank(repo)) { 097 repo = Framework.getLocalService(RepositoryManager.class).getDefaultRepository().getName(); 098 } 099 100 // This try-with-resources does an implicit close() at the end 101 try (CoreSession coreSession = CoreInstance.openCoreSession(repo)) { 102 103 leftDoc = coreSession.getDocument(new IdRef(leftDocId)); 104 rightDoc = coreSession.getDocument(new IdRef(rightDocId)); 105 106 DiffPictures dp = new DiffPictures(leftDoc, rightDoc, xpath); 107 108 HashMap<String, Serializable> params = new HashMap<String, Serializable>(); 109 if (StringUtils.isNotBlank(fuzz)) { 110 params.put("fuzz", fuzz); 111 } 112 if (StringUtils.isNotBlank(highlightColor)) { 113 params.put("highlightColor", highlightColor); 114 } 115 if (StringUtils.isNotBlank(lowlightColor)) { 116 params.put("lowlightColor", lowlightColor); 117 } 118 119 if (StringUtils.isNotBlank(altExtension)) { 120 // Using the leftDoc only 121 Blob leftB; 122 if (StringUtils.isBlank(xpath) || "null".equals(xpath)) { 123 leftB = (Blob) leftDoc.getPropertyValue(DiffPictures.DEFAULT_XPATH); 124 } else { 125 leftB = (Blob) leftDoc.getPropertyValue(xpath); 126 } 127 String fileName = leftB.getFilename(); 128 int dotPos = fileName.lastIndexOf("."); 129 String ext = fileName.substring(dotPos + 1); 130 ext = ext.toLowerCase(); 131 switch (ext) { 132 case "jpg": 133 case "jpeg": 134 case "png": 135 case "gif": 136 // No need to change anything 137 break; 138 139 default: 140 if (altExtension.indexOf(".") != 0) { 141 altExtension = "." + altExtension; 142 } 143 fileName = "comp-" + fileName + altExtension; 144 params.put("targetFileName", fileName); 145 break; 146 147 } 148 } 149 150 Blob bResult; 151 try { 152 bResult = dp.compare(commandLine, params); 153 } catch (CommandNotAvailable | IOException e) { 154 log.error("Unable to compare the pictures", e); 155 sendTextResponse(resp, "Unable to compare the pictures"); 156 return; 157 } 158 159 resp.setHeader("Cache-Control", "no-cache"); 160 resp.setHeader("Pragma", "no-cache"); 161 try { 162 sendBlobResult(req, resp, bResult); 163 } catch (IOException e) { 164 log.error("Unable to handleCompareResult", e); 165 sendTextResponse(resp, "Unable to return the result"); 166 return; 167 } 168 } 169 } 170 171 protected void sendTextResponse(HttpServletResponse resp, String response) throws IOException { 172 173 resp.setContentType("text/plain"); 174 resp.setContentLength(response.getBytes().length); 175 OutputStream out = resp.getOutputStream(); 176 out.write(response.getBytes()); 177 out.close(); 178 179 } 180 181 protected void sendBlobResult(HttpServletRequest req, HttpServletResponse resp, Blob blob) throws IOException { 182 183 InputStream in = blob.getStream(); 184 OutputStream out = resp.getOutputStream(); 185 String fileName = blob.getFilename(); 186 187 resp.setHeader("Content-Disposition", ServletHelper.getRFC2231ContentDisposition(req, fileName)); 188 resp.setContentType(blob.getMimeType()); 189 long fileSize = blob.getLength(); 190 resp.setContentLength((int) fileSize); 191 192 byte[] buffer = new byte[BUFFER_SIZE]; 193 int bytesRead; 194 while ((bytesRead = in.read(buffer)) != -1) { 195 out.write(buffer, 0, bytesRead); 196 } 197 198 } 199}