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