001/*
002 * (C) Copyright 2006-20014 Nuxeo SA (http://nuxeo.com/) and contributors.
003 *
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the GNU Lesser General Public License
006 * (LGPL) version 2.1 which accompanies this distribution, and is available at
007 * http://www.gnu.org/licenses/lgpl-2.1.html
008 *
009 * This library is distributed in the hope that it will be useful,
010 * but WITHOUT ANY WARRANTY; without even the implied warranty of
011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012 * Lesser General Public License for more details.
013 *
014 */
015package org.nuxeo.ecm.platform.preview.adapter.base;
016
017import java.io.File;
018import java.util.ArrayList;
019import java.util.List;
020
021import org.apache.commons.logging.Log;
022import org.apache.commons.logging.LogFactory;
023
024import org.nuxeo.ecm.core.api.Blob;
025import org.nuxeo.ecm.core.api.blobholder.BlobHolder;
026import org.nuxeo.ecm.core.api.blobholder.DocumentBlobHolder;
027import org.nuxeo.ecm.core.convert.api.ConversionException;
028import org.nuxeo.ecm.core.convert.api.ConversionService;
029import org.nuxeo.ecm.platform.mimetype.MimetypeDetectionException;
030import org.nuxeo.ecm.platform.mimetype.MimetypeNotFoundException;
031import org.nuxeo.ecm.platform.mimetype.interfaces.MimetypeRegistry;
032import org.nuxeo.ecm.platform.preview.adapter.MimeTypePreviewer;
033import org.nuxeo.ecm.platform.preview.adapter.PreviewAdapterManager;
034import org.nuxeo.ecm.platform.preview.api.NothingToPreviewException;
035import org.nuxeo.ecm.platform.preview.api.PreviewException;
036import org.nuxeo.runtime.api.Framework;
037
038/**
039 * Base class for preview based on "on the fly" HTML transformers
040 *
041 * @author tiry
042 */
043public class ConverterBasedHtmlPreviewAdapter extends AbstractHtmlPreviewAdapter {
044
045    private static final Log log = LogFactory.getLog(ConverterBasedHtmlPreviewAdapter.class);
046
047    protected String defaultFieldXPath;
048
049    protected MimetypeRegistry mimeTypeService;
050
051    public ConversionService getConversionService() {
052        return Framework.getService(ConversionService.class);
053    }
054
055    @Override
056    protected PreviewAdapterManager getPreviewManager() {
057        return Framework.getService(PreviewAdapterManager.class);
058    }
059
060    protected static String getMimeType(Blob blob) {
061        if (blob == null) {
062            return null;
063        }
064
065        String srcMT = blob.getMimeType();
066        if (srcMT == null || srcMT.startsWith("application/octet-stream")) {
067            // call MT Service
068            try {
069                MimetypeRegistry mtr = Framework.getService(MimetypeRegistry.class);
070                srcMT = mtr.getMimetypeFromFilenameAndBlobWithDefault(blob.getFilename(), blob,
071                        "application/octet-stream");
072                log.debug("mime type service returned " + srcMT);
073            } catch (MimetypeDetectionException e) {
074                log.warn("error while calling Mimetype service", e);
075            }
076        }
077        return srcMT;
078    }
079
080    protected String getDefaultPreviewFieldXPath() {
081        return defaultFieldXPath;
082    }
083
084    public void setDefaultPreviewFieldXPath(String xPath) {
085        defaultFieldXPath = xPath;
086    }
087
088    @Override
089    public List<Blob> getPreviewBlobs() throws PreviewException {
090        return getPreviewBlobs(getDefaultPreviewFieldXPath());
091    }
092
093    @Override
094    public List<Blob> getPreviewBlobs(String xpath) throws PreviewException {
095
096        BlobHolder blobHolder2preview = getBlobHolder2preview(xpath);
097        Blob blob2Preview = getBlob2preview(blobHolder2preview);
098
099        List<Blob> blobResults = new ArrayList<>();
100
101        String srcMT = getMimeType(blob2Preview);
102        log.debug("Source type for HTML preview =" + srcMT);
103        MimeTypePreviewer mtPreviewer = getPreviewManager().getPreviewer(srcMT);
104        if (mtPreviewer != null) {
105            blobResults = mtPreviewer.getPreview(blob2Preview, adaptedDoc);
106            return blobResults;
107        }
108
109        String converterName = getConversionService().getConverterName(srcMT, "text/html");
110        if (converterName == null) {
111            log.debug("No dedicated converter found, using generic");
112            converterName = "any2html";
113        }
114
115        BlobHolder result;
116        try {
117            result = getConversionService().convert(converterName, blobHolder2preview, null);
118            setMimeType(result);
119            return result.getBlobs();
120        } catch (ConversionException e) {
121            throw new PreviewException(e.getMessage(), e);
122        }
123
124    }
125
126    /**
127     * @param blobHolder2preview
128     * @return
129     * @throws PreviewException
130     * @since 5.7.3
131     */
132    private Blob getBlob2preview(BlobHolder blobHolder2preview) throws PreviewException {
133        Blob blob2Preview = blobHolder2preview.getBlob();
134        if (blob2Preview == null) {
135            throw new NothingToPreviewException("Can not preview a document without blob");
136        } else {
137            return blob2Preview;
138        }
139    }
140
141    /**
142     * Returns a blob holder suitable for a preview.
143     *
144     * @param xpath
145     * @param adaptedDoc
146     * @return
147     * @since 5.7.3
148     */
149    private BlobHolder getBlobHolder2preview(String xpath) {
150        if ((xpath == null) || ("default".equals(xpath))) {
151            return adaptedDoc.getAdapter(BlobHolder.class);
152        } else {
153            return new DocumentBlobHolder(adaptedDoc, xpath);
154        }
155    }
156
157    protected void setMimeType(BlobHolder result) {
158        for (Blob blob : result.getBlobs()) {
159            if ((blob.getMimeType() == null || blob.getMimeType().startsWith("application/octet-stream"))
160                    && blob.getFilename().endsWith("html")) {
161                String mimeTpye = getMimeType(blob);
162                blob.setMimeType(mimeTpye);
163            }
164        }
165    }
166
167    public String getMimeType(File file) throws ConversionException {
168        try {
169            return getMimeTypeService().getMimetypeFromFile(file);
170        } catch (ConversionException e) {
171            throw new ConversionException("Could not get MimeTypeRegistry");
172        } catch (MimetypeNotFoundException e) {
173            return "application/octet-stream";
174        } catch (MimetypeDetectionException e) {
175            return "application/octet-stream";
176        }
177    }
178
179    public MimetypeRegistry getMimeTypeService() throws ConversionException {
180        if (mimeTypeService == null) {
181            mimeTypeService = Framework.getService(MimetypeRegistry.class);
182        }
183        return mimeTypeService;
184    }
185
186    @Override
187    public void cleanup() {
188
189    }
190
191    @Override
192    public boolean cachable() {
193        return true;
194    }
195
196    @Override
197    public boolean hasBlobToPreview() throws PreviewException {
198        String xpath = getDefaultPreviewFieldXPath();
199        Blob blob2Preview;
200        try {
201            blob2Preview = getBlob2preview(getBlobHolder2preview(xpath));
202        } catch (NothingToPreviewException e) {
203            return false;
204        }
205        if (blob2Preview == null) {
206            return false;
207        }
208        return true;
209    }
210
211}