001/* 002 * (C) Copyright 2006-2016 Nuxeo SA (http://nuxeo.com/) and others. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 * 016 * Contributors: 017 * Nuxeo - initial API and implementation 018 * Florent Bonnet <florent.bonnet@nuxeo.com> 019 * Estelle Giuly <egiuly@nuxeo.com> 020 * 021 * $Id: JOOoConvertPluginImpl.java 18651 2007-05-13 20:28:53Z sfermigier $ 022 */ 023 024package org.nuxeo.ecm.webapp.action; 025 026import static org.nuxeo.ecm.platform.mimetype.interfaces.MimetypeRegistry.PDF_MIMETYPE; 027import static org.nuxeo.ecm.platform.mimetype.interfaces.MimetypeRegistry.PDF_EXTENSION; 028 029import java.io.IOException; 030import java.net.URI; 031import java.util.Collections; 032import java.util.HashMap; 033import java.util.Iterator; 034import java.util.Map; 035 036import javax.faces.context.FacesContext; 037 038import org.apache.commons.lang3.StringUtils; 039import org.apache.commons.logging.Log; 040import org.apache.commons.logging.LogFactory; 041import org.jboss.seam.ScopeType; 042import org.jboss.seam.annotations.In; 043import org.jboss.seam.annotations.Name; 044import org.jboss.seam.annotations.Scope; 045import org.jboss.seam.annotations.remoting.WebRemote; 046import org.jboss.seam.annotations.web.RequestParameter; 047import org.nuxeo.ecm.core.api.Blob; 048import org.nuxeo.ecm.core.api.CoreSession; 049import org.nuxeo.ecm.core.api.DocumentModel; 050import org.nuxeo.ecm.core.api.IdRef; 051import org.nuxeo.ecm.core.api.blobholder.BlobHolder; 052import org.nuxeo.ecm.core.api.blobholder.DocumentBlobHolder; 053import org.nuxeo.ecm.core.blob.BlobManager; 054import org.nuxeo.ecm.core.blob.BlobManager.UsageHint; 055import org.nuxeo.ecm.core.convert.api.ConversionService; 056import org.nuxeo.ecm.core.convert.api.ConverterCheckResult; 057import org.nuxeo.ecm.core.convert.api.ConverterNotRegistered; 058import org.nuxeo.ecm.platform.mimetype.interfaces.MimetypeRegistry; 059import org.nuxeo.ecm.platform.ui.web.api.NavigationContext; 060import org.nuxeo.ecm.platform.ui.web.cache.ThreadSafeCacheHolder; 061import org.nuxeo.ecm.platform.ui.web.util.ComponentUtils; 062import org.nuxeo.runtime.api.Framework; 063 064@Name("conversionActions") 065@Scope(ScopeType.EVENT) 066public class ConversionActionBean implements ConversionAction { 067 068 private static final Log log = LogFactory.getLog(ConversionActionBean.class); 069 070 protected Map<String, ConverterCheckResult> pdfConverterForTypes; 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<>(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 return blob != null && isExportableToPDF(blob); 119 } 120 121 @Override 122 public boolean isExportableToPDF(Blob blob) { 123 if (blob == null) { 124 return false; 125 } 126 // check if there's a conversion available 127 if (getPDFConversionURL(blob) != null) { 128 return true; 129 } 130 String mimeType = blob.getMimeType(); 131 return isMimeTypeExportableToPDF(mimeType); 132 } 133 134 protected String getPDFConversionURL(Blob blob) { 135 BlobManager blobManager = Framework.getService(BlobManager.class); 136 try { 137 URI uri = blobManager.getAvailableConversions(blob, UsageHint.DOWNLOAD).get(PDF_MIMETYPE); 138 if (uri != null) { 139 return uri.toString(); 140 } 141 } catch (IOException e) { 142 log.error("Failed to retrieve available conversions", e); 143 } 144 return null; 145 } 146 147 protected boolean isMimeTypeExportableToPDF(String mimeType) { 148 // Don't bother searching for NO MIME type. 149 if (mimeType == null) { 150 return false; 151 } 152 153 // Initialize the converter check result map. 154 if (pdfConverterForTypes == null) { 155 pdfConverterForTypes = new HashMap<>(); 156 } 157 158 // Check if there is any saved ConverterCheckResult for the desired 159 // MIME type. 160 if (pdfConverterForTypes.containsKey(mimeType)) { 161 return pdfConverterForTypes.get(mimeType).isAvailable(); 162 } 163 164 try { 165 ConverterCheckResult pdfConverterAvailability; 166 ConversionService conversionService = Framework.getService(ConversionService.class); 167 Iterator<String> converterNames = conversionService.getConverterNames(mimeType, PDF_MIMETYPE).iterator(); 168 while (converterNames.hasNext()) { 169 pdfConverterName = converterNames.next(); 170 pdfConverterAvailability = conversionService.isConverterAvailable(pdfConverterName, true); 171 172 // Save the converter availability for all the mime-types the 173 // converter 174 // supports. 175 for (String supMimeType : pdfConverterAvailability.getSupportedInputMimeTypes()) { 176 pdfConverterForTypes.put(supMimeType, pdfConverterAvailability); 177 } 178 179 if (pdfConverterAvailability.isAvailable()) { 180 return true; 181 } 182 } 183 } catch (ConverterNotRegistered e) { 184 log.error("Error while testing PDF converter availability", e); 185 } 186 return false; 187 } 188 189 @Override 190 @WebRemote 191 public boolean isFileExportableToPDF(String fieldName) { 192 DocumentModel doc = getDocument(); 193 Boolean cacheResult = exportableToPDFCache.getFromCache(doc, fieldName); 194 boolean isSupported; 195 if (cacheResult == null) { 196 String mimetype = getMimetypeFromDocument(fieldName); 197 isSupported = isMimeTypeExportableToPDF(mimetype); 198 exportableToPDFCache.addToCache(doc, fieldName, isSupported); 199 } else { 200 isSupported = cacheResult; 201 } 202 return isSupported; 203 } 204 205 public String generatePdfFileFromBlobHolder(DocumentModel doc, BlobHolder bh) throws IOException { 206 // redirect to the conversion URL when available 207 Blob blob = bh.getBlob(); 208 String url = getPDFConversionURL(blob); 209 if (url != null) { 210 try { 211 FacesContext.getCurrentInstance().getExternalContext().redirect(url); 212 return null; 213 } catch (IOException e) { 214 // 215 } 216 } 217 if (pdfConverterName == null) { 218 log.error("No PDF converter was found."); 219 return "pdf_generation_error"; 220 } 221 Blob result = Framework.getService(ConversionService.class) 222 .convertToMimeType(MimetypeRegistry.PDF_MIMETYPE, bh, Collections.emptyMap()) 223 .getBlob(); 224 if (result == null) { 225 log.error("Transform service didn't return any resulting documents which is not normal."); 226 return "pdf_generation_error"; 227 } 228 String xpath; 229 if (bh instanceof DocumentBlobHolder) { 230 xpath = ((DocumentBlobHolder) bh).getXpath(); 231 } else { 232 xpath = null; 233 } 234 ComponentUtils.download(doc, xpath, result, result.getFilename(), "pdfConversion"); 235 return null; 236 } 237 238 @Override 239 @WebRemote 240 public String generatePdfFile() throws IOException { 241 DocumentModel doc = getDocument(); 242 BlobHolder bh = new DocumentBlobHolder(doc, fileFieldFullName); 243 return generatePdfFileFromBlobHolder(doc, bh); 244 } 245 246 /** 247 * @since 7.3 248 */ 249 public boolean isPDF(BlobHolder bh) { 250 if (bh == null) { 251 return false; 252 } 253 Blob blob = bh.getBlob(); 254 return blob != null && isPDF(blob); 255 } 256 257 /** 258 * @since 7.3 259 */ 260 public boolean isPDF(Blob blob) { 261 if (blob == null) { 262 return false; 263 } 264 String mimeType = blob.getMimeType(); 265 if (StringUtils.isNotBlank(mimeType) && PDF_MIMETYPE.equals(mimeType)) { 266 return true; 267 } else { 268 String filename = blob.getFilename(); 269 if (StringUtils.isNotBlank(filename) && filename.endsWith(PDF_EXTENSION)) { 270 // assume it's a pdf file 271 return true; 272 } 273 } 274 return false; 275 } 276 277 public void initialize() { 278 // NOP 279 } 280 281}