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