001/*
002 * (C) Copyright 2002-2010 Nuxeo SAS (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.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 * Contributors:
015 *     Nuxeo - initial API and implementation
016 *
017 */
018package org.nuxeo.ecm.platform.convert.plugins;
019
020import java.io.File;
021import java.io.IOException;
022import java.util.ArrayList;
023import java.util.List;
024
025import org.apache.commons.lang.StringEscapeUtils;
026import org.apache.commons.logging.Log;
027import org.apache.commons.logging.LogFactory;
028import org.nuxeo.common.utils.FileUtils;
029import org.nuxeo.common.utils.Path;
030import org.nuxeo.common.utils.ZipUtils;
031import org.nuxeo.ecm.core.api.Blob;
032import org.nuxeo.ecm.core.api.Blobs;
033import org.nuxeo.ecm.core.api.NuxeoException;
034import org.nuxeo.ecm.core.convert.api.ConversionException;
035import org.nuxeo.ecm.core.convert.cache.SimpleCachableBlobHolder;
036import org.nuxeo.ecm.platform.mimetype.MimetypeDetectionException;
037import org.nuxeo.ecm.platform.mimetype.MimetypeNotFoundException;
038import org.nuxeo.ecm.platform.mimetype.interfaces.MimetypeRegistry;
039import org.nuxeo.runtime.api.Framework;
040
041/**
042 * Cachable implementation of a zip file.
043 *
044 * @author Laurent Doguin
045 */
046public class ZipCachableBlobHolder extends SimpleCachableBlobHolder {
047
048    private static final Log log = LogFactory.getLog(ZipCachableBlobHolder.class);
049
050    protected Blob zipBlob;
051
052    protected MimetypeRegistry mimeTypeService;
053
054    protected String key;
055
056    public ZipCachableBlobHolder() {
057    }
058
059    public ZipCachableBlobHolder(Blob zipBlob) {
060        this.zipBlob = zipBlob;
061    }
062
063    public Blob getBlob(String path) throws IOException, MimetypeNotFoundException, MimetypeDetectionException,
064            ConversionException {
065        String filePath = key + path;
066        File file = new File(filePath);
067        Blob blob = Blobs.createBlob(file);
068        String mimeType = getMimeTypeService().getMimetypeFromBlob(blob);
069        blob.setMimeType(mimeType);
070        blob.setFilename(path);
071        return blob;
072    }
073
074    @Override
075    public Blob getBlob() {
076        return zipBlob;
077    }
078
079    @Override
080    public List<Blob> getBlobs() {
081        if (blobs == null) {
082            try {
083                load(key);
084            } catch (IOException e) {
085                throw new NuxeoException(e);
086            }
087        }
088        return blobs;
089    }
090
091    @Override
092    public void load(String path) throws IOException {
093        blobs = new ArrayList<Blob>();
094        File base = new File(path);
095        try {
096            if (base.isDirectory()) {
097                addDirectoryToList(base, "");
098            } else {
099                File file = new File(path);
100                String mimeType = getMimeType(file);
101                Blob mainBlob = Blobs.createBlob(file, mimeType, null, file.getName());
102                blobs.add(mainBlob);
103            }
104
105            orderIndexPageFirst(blobs);
106        } catch (ConversionException e) {
107            throw new RuntimeException("Blob loading from cache failed", e.getCause());
108        }
109    }
110
111    @Override
112    public String persist(String basePath) throws IOException {
113        Path path = new Path(basePath);
114        path = path.append(getHash());
115        File dir = new File(path.toString());
116        dir.mkdir();
117        ZipUtils.unzip(zipBlob.getStream(), dir);
118        key = dir.getAbsolutePath();
119
120        // Check if creating an index.html file is needed
121        load(path.toString());
122        if (blobs != null && !blobs.get(0).getFilename().contains("index.html")) {
123            log.info("Any index.html file found, generate a listing as index page.");
124            File index = new File(dir, "index.html");
125            if (index.createNewFile()) {
126                Blob indexBlob = createIndexBlob();
127                blobs.add(0, indexBlob);
128                FileUtils.writeFile(index, indexBlob.getByteArray());
129            } else {
130                log.info("Unable to create index.html file");
131            }
132        }
133
134        return key;
135    }
136
137    public String getMimeType(File file) throws ConversionException {
138        try {
139            return getMimeTypeService().getMimetypeFromFile(file);
140        } catch (ConversionException e) {
141            throw new ConversionException("Could not get MimeTypeRegistry", e);
142        } catch (MimetypeNotFoundException | MimetypeDetectionException e) {
143            return "application/octet-stream";
144        }
145    }
146
147    public MimetypeRegistry getMimeTypeService() throws ConversionException {
148        if (mimeTypeService == null) {
149            mimeTypeService = Framework.getService(MimetypeRegistry.class);
150        }
151        return mimeTypeService;
152    }
153
154    protected Blob createIndexBlob() {
155        StringBuilder page = new StringBuilder("<html><body>");
156        page.append("<h1>").append(StringEscapeUtils.escapeJavaScript(StringEscapeUtils.escapeHtml(zipBlob.getFilename()))).append("</h1>");
157        page.append("<ul>");
158        for (Blob blob : blobs) {
159            String fn = StringEscapeUtils.escapeJavaScript(StringEscapeUtils.escapeHtml(blob.getFilename()));
160            page.append("<li><a href=\"").append(fn).append("\">");
161            page.append(fn);
162            page.append("</a></li>");
163        }
164        page.append("</ul></body></html>");
165        return Blobs.createBlob(page.toString());
166    }
167}