001/* 002 * (C) Copyright 2017 Nuxeo (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 * Florent Guillaume 018 */ 019package org.nuxeo.ecm.webengine.model.io; 020 021import java.io.IOException; 022import java.io.OutputStream; 023import java.lang.annotation.Annotation; 024import java.lang.reflect.Type; 025 026import javax.servlet.http.HttpServletRequest; 027import javax.servlet.http.HttpServletResponse; 028import javax.ws.rs.Produces; 029import javax.ws.rs.core.Context; 030import javax.ws.rs.core.MediaType; 031import javax.ws.rs.core.MultivaluedMap; 032import javax.ws.rs.ext.MessageBodyWriter; 033import javax.ws.rs.ext.Provider; 034 035import org.nuxeo.ecm.core.api.Blob; 036import org.nuxeo.ecm.core.api.DocumentModel; 037import org.nuxeo.ecm.core.api.blobholder.DocumentBlobHolder; 038import org.nuxeo.ecm.core.io.download.BufferingServletOutputStream; 039import org.nuxeo.ecm.core.io.download.DownloadService; 040import org.nuxeo.runtime.api.Framework; 041import org.nuxeo.runtime.transaction.TransactionHelper; 042 043/** 044 * Writer for a {@link DocumentBlobHolder}, keeping the context of the current document, which allows for later 045 * filtering by the {@link DownloadService}. 046 * 047 * @since 9.3 048 */ 049@Provider 050@Produces({ "*/*", "text/plain" }) 051public class DocumentBlobHolderWriter implements MessageBodyWriter<DocumentBlobHolder> { 052 053 @Context 054 protected HttpServletRequest request; 055 056 @Context 057 protected HttpServletResponse response; 058 059 @Override 060 public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) { 061 return DocumentBlobHolder.class.isAssignableFrom(type); 062 } 063 064 @Override 065 public long getSize(DocumentBlobHolder blobHolder, Class<?> type, Type genericType, Annotation[] annotations, 066 MediaType mediaType) { 067 long n = blobHolder.getBlob().getLength(); 068 return n < 0 ? -1 : n; 069 } 070 071 @Override 072 public void writeTo(DocumentBlobHolder blobHolder, Class<?> type, Type genericType, Annotation[] annotations, 073 MediaType mediaType, MultivaluedMap<String, Object> httpHeaders, OutputStream entityStream) 074 throws IOException { 075 // ensure transaction is committed before writing blob to response 076 commitAndReopenTransaction(); 077 Blob blob = blobHolder.getBlob(); 078 if (Framework.isTestModeSet()) { 079 transferBlob(blob, entityStream); 080 return; 081 } 082 DocumentModel doc = blobHolder.getDocument(); 083 String xpath = blobHolder.getXpath(); 084 DownloadService downloadService = Framework.getService(DownloadService.class); 085 downloadService.downloadBlob(request, response, doc, xpath, blob, blob.getFilename(), "download"); 086 } 087 088 protected void commitAndReopenTransaction() { 089 if (TransactionHelper.isTransactionActiveOrMarkedRollback()) { 090 TransactionHelper.commitOrRollbackTransaction(); 091 TransactionHelper.startTransaction(); 092 } 093 } 094 095 protected void transferBlob(Blob blob, OutputStream entityStream) throws IOException { 096 if (entityStream instanceof BufferingServletOutputStream) { 097 ((BufferingServletOutputStream) entityStream).stopBuffering(); 098 } 099 blob.transferTo(entityStream); 100 entityStream.flush(); 101 } 102 103}