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