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