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