001/* 002 * (C) Copyright 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 * 018 * Nelson Silva <[email protected]> 019 */ 020package org.nuxeo.ecm.restapi.server.jaxrs.adapters; 021 022import static javax.ws.rs.core.Response.Status.NOT_FOUND; 023 024import java.io.IOException; 025import java.io.Serializable; 026import java.net.URI; 027import java.util.Collections; 028import java.util.List; 029import java.util.Map; 030import java.util.Optional; 031 032import javax.servlet.http.HttpServletRequest; 033import javax.servlet.http.HttpServletResponse; 034import javax.ws.rs.GET; 035import javax.ws.rs.Path; 036import javax.ws.rs.PathParam; 037import javax.ws.rs.Produces; 038import javax.ws.rs.QueryParam; 039import javax.ws.rs.core.Context; 040import javax.ws.rs.core.MediaType; 041import javax.ws.rs.core.Response; 042 043import org.nuxeo.ecm.core.api.Blob; 044import org.nuxeo.ecm.core.api.DocumentModel; 045import org.nuxeo.ecm.core.api.NuxeoException; 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.io.download.DownloadService; 050import org.nuxeo.ecm.platform.preview.api.HtmlPreviewAdapter; 051import org.nuxeo.ecm.platform.preview.api.PreviewException; 052import org.nuxeo.ecm.platform.preview.helper.PreviewHelper; 053import org.nuxeo.ecm.restapi.server.jaxrs.blob.BlobObject; 054import org.nuxeo.ecm.webengine.model.Resource; 055import org.nuxeo.ecm.webengine.model.WebAdapter; 056import org.nuxeo.ecm.webengine.model.exceptions.WebResourceNotFoundException; 057import org.nuxeo.ecm.webengine.model.impl.DefaultAdapter; 058import org.nuxeo.runtime.api.Framework; 059 060/** 061 * @since 8.2 062 */ 063@WebAdapter(name = PreviewAdapter.NAME, type = "previewAdapter") 064@Produces({ MediaType.APPLICATION_JSON }) 065public class PreviewAdapter extends DefaultAdapter { 066 067 public static final String NAME = "preview"; 068 069 @GET 070 public Object preview(@QueryParam("blobPostProcessing") boolean postProcessing, @Context HttpServletRequest request, 071 @Context HttpServletResponse response) { 072 073 DocumentBlobHolder bh = getBlobHolderToPreview(); 074 if (bh == null) { 075 return Response.status(NOT_FOUND).build(); 076 } 077 078 // if it's a managed blob try to use the embed uri for preview 079 BlobManager blobManager = Framework.getService(BlobManager.class); 080 try { 081 URI uri = blobManager.getURI(bh.getBlob(), BlobManager.UsageHint.EMBED, null); 082 if (uri != null) { 083 return Response.seeOther(uri).build(); 084 } 085 } catch (IOException e) { 086 throw new NuxeoException(e); 087 } 088 089 List<Blob> previewBlobs = getPreviewBlobs(bh, postProcessing); 090 if (previewBlobs == null || previewBlobs.isEmpty()) { 091 throw new WebResourceNotFoundException("Preview not available"); 092 } 093 094 try { 095 Blob blob = previewBlobs.get(0); 096 DownloadService downloadService = Framework.getService(DownloadService.class); 097 downloadService.downloadBlob(request, response, bh.getDocument(), bh.getXpath(), blob, blob.getFilename(), 098 "preview", null, true); 099 } catch (IOException e) { 100 throw new NuxeoException(e); 101 } 102 103 return Response.ok().build(); 104 } 105 106 @GET 107 @Path("{subPath}") 108 public Object subPath(@PathParam("subPath") String subPath, 109 @QueryParam("blobPostProcessing") boolean postProcessing, @Context HttpServletRequest request, 110 @Context HttpServletResponse response) { 111 112 DocumentBlobHolder bh = getBlobHolderToPreview(); 113 if (bh == null) { 114 return Response.status(NOT_FOUND).build(); 115 } 116 117 List<Blob> previewBlobs = getPreviewBlobs(bh, postProcessing); 118 if (previewBlobs == null || previewBlobs.isEmpty()) { 119 throw new WebResourceNotFoundException("Preview not available"); 120 } 121 122 // find blob 123 Optional<Blob> subBlob = previewBlobs.stream().filter(b -> subPath.equals(b.getFilename())).findFirst(); 124 125 if (!subBlob.isPresent()) { 126 throw new WebResourceNotFoundException(String.format("Preview blob %s not found", subPath)); 127 } 128 129 try { 130 Blob blob = subBlob.get(); 131 DownloadService downloadService = Framework.getService(DownloadService.class); 132 Map<String, Serializable> extendedInfos = Collections.singletonMap("subPath", subPath); 133 downloadService.downloadBlob(request, response, bh.getDocument(), bh.getXpath(), blob, blob.getFilename(), 134 "preview", extendedInfos, true); 135 } catch (IOException e) { 136 throw new NuxeoException(e); 137 } 138 139 return Response.ok().build(); 140 } 141 142 private List<Blob> getPreviewBlobs(DocumentBlobHolder bh, boolean blobPostProcessing) { 143 DocumentModel doc = bh.getDocument(); 144 String xpath = bh.getXpath(); 145 HtmlPreviewAdapter preview; 146 147 try { 148 if (isBlobTarget() && !isBlobHolder(doc, xpath)) { 149 preview = PreviewHelper.getBlobPreviewAdapter(doc); 150 return preview.getFilePreviewBlobs(xpath, blobPostProcessing); 151 } 152 153 preview = doc.getAdapter(HtmlPreviewAdapter.class); 154 if (preview == null) { 155 return null; 156 } 157 158 return preview.getFilePreviewBlobs(blobPostProcessing); 159 } catch (PreviewException e) { 160 throw new WebResourceNotFoundException("Preview not available", e); 161 } 162 } 163 164 private DocumentBlobHolder getBlobHolderToPreview() { 165 Resource target = getTarget(); 166 if (isBlobTarget()) { 167 return ((BlobObject) target).getBlobHolder(); 168 } else { 169 DocumentModel doc = target.getAdapter(DocumentModel.class); 170 return (DocumentBlobHolder) doc.getAdapter(BlobHolder.class); 171 } 172 } 173 174 private boolean isBlobTarget() { 175 return getTarget().isInstanceOf("blob"); 176 } 177 178 private boolean isBlobHolder(DocumentModel doc, String xpath) { 179 DocumentBlobHolder bh = (DocumentBlobHolder) doc.getAdapter(BlobHolder.class); 180 return bh != null && bh.getXpath().equals(xpath); 181 } 182}