001/* 002 * (C) Copyright 2006-2007 Nuxeo SAS (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.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 * Nuxeo - initial API and implementation 016 * 017 * $Id: JOOoConvertPluginImpl.java 18651 2007-05-13 20:28:53Z sfermigier $ 018 */ 019 020package org.nuxeo.ecm.webapp.action; 021 022import java.io.IOException; 023import java.net.URI; 024import java.util.HashMap; 025import java.util.Iterator; 026import java.util.Map; 027 028import javax.faces.context.FacesContext; 029 030import org.apache.commons.lang.StringUtils; 031import org.apache.commons.logging.Log; 032import org.apache.commons.logging.LogFactory; 033import org.jboss.seam.ScopeType; 034import org.jboss.seam.annotations.In; 035import org.jboss.seam.annotations.Name; 036import org.jboss.seam.annotations.Scope; 037import org.jboss.seam.annotations.remoting.WebRemote; 038import org.jboss.seam.annotations.web.RequestParameter; 039import org.nuxeo.common.utils.Path; 040import org.nuxeo.ecm.core.api.Blob; 041import org.nuxeo.ecm.core.api.CoreSession; 042import org.nuxeo.ecm.core.api.DocumentModel; 043import org.nuxeo.ecm.core.api.IdRef; 044import org.nuxeo.ecm.core.api.blobholder.BlobHolder; 045import org.nuxeo.ecm.core.api.blobholder.DocumentBlobHolder; 046import org.nuxeo.ecm.core.blob.BlobManager; 047import org.nuxeo.ecm.core.blob.BlobManager.UsageHint; 048import org.nuxeo.ecm.core.convert.api.ConversionService; 049import org.nuxeo.ecm.core.convert.api.ConverterCheckResult; 050import org.nuxeo.ecm.core.convert.api.ConverterNotRegistered; 051import org.nuxeo.ecm.platform.ui.web.api.NavigationContext; 052import org.nuxeo.ecm.platform.ui.web.cache.ThreadSafeCacheHolder; 053import org.nuxeo.ecm.platform.ui.web.util.ComponentUtils; 054import org.nuxeo.ecm.platform.ui.web.util.files.FileUtils; 055import org.nuxeo.runtime.api.Framework; 056 057/** 058 * @author <a href="mailto:florent.bonnet@nuxeo.com">Florent BONNET</a> 059 */ 060@Name("conversionActions") 061@Scope(ScopeType.EVENT) 062public class ConversionActionBean implements ConversionAction { 063 064 private static final Log log = LogFactory.getLog(ConversionActionBean.class); 065 066 protected Map<String, ConverterCheckResult> pdfConverterForTypes; 067 068 protected static final String PDF_MIMETYPE = "application/pdf"; 069 070 protected static final String PDF_EXTENSION = ".pdf"; 071 072 @In(create = true, required = false) 073 CoreSession documentManager; 074 075 @In(create = true) 076 NavigationContext navigationContext; 077 078 @RequestParameter 079 private String docRef; 080 081 @RequestParameter 082 private String fileFieldFullName; 083 084 @RequestParameter 085 private String filename; 086 087 protected String pdfConverterName; 088 089 protected static final ThreadSafeCacheHolder<Boolean> exportableToPDFCache = new ThreadSafeCacheHolder<Boolean>(20); 090 091 public String display() { 092 return "view_file"; 093 } 094 095 private DocumentModel getDocument() { 096 if (docRef == null) { 097 return navigationContext.getCurrentDocument(); 098 } else { 099 return documentManager.getDocument(new IdRef(docRef)); 100 } 101 } 102 103 private String getMimetypeFromDocument(String propertyName) { 104 Blob blob = (Blob) getDocument().getPropertyValue(propertyName); 105 return blob.getMimeType(); 106 } 107 108 @Override 109 public void reCheckConverterAvailability() { 110 pdfConverterForTypes.clear(); 111 } 112 113 public boolean isExportableToPDF(BlobHolder bh) { 114 if (bh == null) { 115 return false; 116 } 117 Blob blob = bh.getBlob(); 118 if (blob == null) { 119 return false; 120 } else { 121 return isExportableToPDF(blob); 122 } 123 } 124 125 @Override 126 public boolean isExportableToPDF(Blob blob) { 127 if (blob == null) { 128 return false; 129 } 130 // check if there's a conversion available 131 if (getPDFConversionURL(blob) != null) { 132 return true; 133 } 134 String mimetype = blob.getMimeType(); 135 return isMimeTypeExportableToPDF(mimetype); 136 } 137 138 protected String getPDFConversionURL(Blob blob) { 139 BlobManager blobManager = Framework.getService(BlobManager.class); 140 try { 141 URI uri = blobManager.getAvailableConversions(blob, UsageHint.DOWNLOAD).get(PDF_MIMETYPE); 142 if (uri != null) { 143 return uri.toString(); 144 } 145 } catch (IOException e) { 146 log.error("Failed to retrieve available conversions", e); 147 } 148 return null; 149 } 150 151 protected boolean isMimeTypeExportableToPDF(String mimetype) { 152 // Don't bother searching for NO MIME type. 153 if (mimetype == null) { 154 return false; 155 } 156 157 // Initialize the converter check result map. 158 if (pdfConverterForTypes == null) { 159 pdfConverterForTypes = new HashMap<String, ConverterCheckResult>(); 160 } 161 162 // Check if there is any saved ConverterCheckResult for the desired 163 // MIME type. 164 if (pdfConverterForTypes.containsValue(mimetype)) { 165 return pdfConverterForTypes.get(mimetype).isAvailable(); 166 } 167 168 try { 169 ConverterCheckResult pdfConverterAvailability; 170 ConversionService conversionService = Framework.getLocalService(ConversionService.class); 171 Iterator<String> converterNames = conversionService.getConverterNames(mimetype, PDF_MIMETYPE).iterator(); 172 while (converterNames.hasNext()) { 173 pdfConverterName = converterNames.next(); 174 pdfConverterAvailability = conversionService.isConverterAvailable(pdfConverterName, true); 175 176 // Save the converter availability for all the mime-types the 177 // converter 178 // supports. 179 for (String supMimeType : pdfConverterAvailability.getSupportedInputMimeTypes()) { 180 pdfConverterForTypes.put(supMimeType, pdfConverterAvailability); 181 } 182 183 if (pdfConverterAvailability.isAvailable()) { 184 return true; 185 } 186 } 187 } catch (ConverterNotRegistered e) { 188 log.error("Error while testing PDF converter availability", e); 189 } 190 return false; 191 } 192 193 @Override 194 @WebRemote 195 public boolean isFileExportableToPDF(String fieldName) { 196 DocumentModel doc = getDocument(); 197 Boolean cacheResult = exportableToPDFCache.getFromCache(doc, fieldName); 198 boolean isSupported; 199 if (cacheResult == null) { 200 String mimetype = getMimetypeFromDocument(fieldName); 201 isSupported = isMimeTypeExportableToPDF(mimetype); 202 exportableToPDFCache.addToCache(doc, fieldName, isSupported); 203 } else { 204 isSupported = cacheResult; 205 } 206 return isSupported; 207 } 208 209 public String generatePdfFileFromBlobHolder(DocumentModel doc, BlobHolder bh) { 210 // redirect to the conversion URL when available 211 Blob blob = bh.getBlob(); 212 String url = getPDFConversionURL(blob); 213 if (url != null) { 214 try { 215 FacesContext.getCurrentInstance().getExternalContext().redirect(url); 216 return null; 217 } catch (IOException e) { 218 // 219 } 220 } 221 if (pdfConverterName == null) { 222 log.error("No PDF converter was found."); 223 return "pdf_generation_error"; 224 } 225 BlobHolder result = Framework.getService(ConversionService.class).convert(pdfConverterName, bh, null); 226 if (result == null) { 227 log.error("Transform service didn't return any resulting documents which is not normal."); 228 return "pdf_generation_error"; 229 } 230 String xpath; 231 if (bh instanceof DocumentBlobHolder) { 232 xpath = ((DocumentBlobHolder) bh).getXpath(); 233 } else { 234 xpath = null; 235 } 236 String origFilename = new Path(bh.getFilePath()).lastSegment(); 237 String filename = FileUtils.getCleanFileName(origFilename); 238 if (StringUtils.isBlank(filename)) { 239 filename = "file"; 240 } 241 // add pdf extension 242 int pos = filename.lastIndexOf('.'); 243 if (pos > 0) { 244 filename = filename.substring(0, pos); 245 } 246 filename += ".pdf"; 247 ComponentUtils.download(doc, xpath, result.getBlob(), filename, "pdfConversion"); 248 return null; 249 } 250 251 @Override 252 @WebRemote 253 public String generatePdfFile() { 254 DocumentModel doc = getDocument(); 255 BlobHolder bh = new DocumentBlobHolder(doc, fileFieldFullName); 256 return generatePdfFileFromBlobHolder(doc, bh); 257 } 258 259 /** 260 * @since 7.3 261 */ 262 public boolean isPDF(BlobHolder bh) { 263 if (bh == null) { 264 return false; 265 } 266 Blob blob = bh.getBlob(); 267 return blob != null && isPDF(blob); 268 } 269 270 /** 271 * @since 7.3 272 */ 273 public boolean isPDF(Blob blob) { 274 if (blob == null) { 275 return false; 276 } 277 String mimeType = blob.getMimeType(); 278 if (StringUtils.isNotBlank(mimeType) && PDF_MIMETYPE.equals(mimeType)) { 279 return true; 280 } else { 281 String filename = blob.getFilename(); 282 if (StringUtils.isNotBlank(filename) && filename.endsWith(PDF_EXTENSION)) { 283 // assume it's a pdf file 284 return true; 285 } 286 } 287 return false; 288 } 289 290 public void initialize() { 291 // NOP 292 } 293 294}