001/*
002 * (C) Copyright 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 * Contributors:
014 * Nuxeo - initial API and implementation
015 */
016package org.nuxeo.ecm.platform.rendition.service;
017
018import static org.nuxeo.ecm.platform.rendition.Constants.FILES_FILES_PROPERTY;
019import static org.nuxeo.ecm.platform.rendition.Constants.FILES_SCHEMA;
020import static org.nuxeo.ecm.platform.rendition.Constants.RENDITION_FACET;
021import static org.nuxeo.ecm.platform.rendition.Constants.RENDITION_NAME_PROPERTY;
022import static org.nuxeo.ecm.platform.rendition.Constants.RENDITION_SOURCE_ID_PROPERTY;
023import static org.nuxeo.ecm.platform.rendition.Constants.RENDITION_SOURCE_VERSIONABLE_ID_PROPERTY;
024
025import java.io.Serializable;
026import java.util.ArrayList;
027import java.util.Map;
028
029import org.apache.commons.logging.Log;
030import org.apache.commons.logging.LogFactory;
031import org.nuxeo.ecm.core.api.Blob;
032import org.nuxeo.ecm.core.api.CoreSession;
033import org.nuxeo.ecm.core.api.DocumentModel;
034import org.nuxeo.ecm.core.api.DocumentModelList;
035import org.nuxeo.ecm.core.api.DocumentRef;
036import org.nuxeo.ecm.core.api.IdRef;
037import org.nuxeo.ecm.core.api.LifeCycleConstants;
038import org.nuxeo.ecm.core.api.UnrestrictedSessionRunner;
039import org.nuxeo.ecm.core.api.VersioningOption;
040import org.nuxeo.ecm.core.api.blobholder.BlobHolder;
041import org.nuxeo.ecm.core.api.blobholder.DocumentStringBlobHolder;
042import org.nuxeo.ecm.core.api.security.ACE;
043import org.nuxeo.ecm.core.api.security.ACL;
044import org.nuxeo.ecm.core.api.security.ACP;
045import org.nuxeo.ecm.core.api.security.SecurityConstants;
046import org.nuxeo.ecm.core.api.security.impl.ACLImpl;
047import org.nuxeo.ecm.core.api.security.impl.ACPImpl;
048import org.nuxeo.ecm.core.versioning.VersioningService;
049import org.nuxeo.ecm.platform.mimetype.interfaces.MimetypeEntry;
050import org.nuxeo.ecm.platform.mimetype.interfaces.MimetypeRegistry;
051import org.nuxeo.runtime.api.Framework;
052
053/**
054 * @author <a href="mailto:troger@nuxeo.com">Thomas Roger</a>
055 */
056public class RenditionCreator extends UnrestrictedSessionRunner {
057
058    private static final Log log = LogFactory.getLog(RenditionCreator.class);
059
060    public static final String FILE = "File";
061
062    protected DocumentRef renditionRef;
063
064    protected DocumentModel detachedDendition;
065
066    protected String liveDocumentId;
067
068    protected DocumentRef versionDocumentRef;
069
070    protected Blob renditionBlob;
071
072    protected String renditionName;
073
074    public RenditionCreator(CoreSession session, DocumentModel liveDocument, DocumentModel versionDocument,
075            Blob renditionBlob, String renditionName) {
076        super(session);
077        liveDocumentId = liveDocument.getId();
078        versionDocumentRef = versionDocument.getRef();
079        this.renditionBlob = renditionBlob;
080        this.renditionName = renditionName;
081    }
082
083    public DocumentRef getRenditionDocumentRef() {
084        return renditionRef;
085    }
086
087    public DocumentModel getDetachedDendition() {
088        return detachedDendition;
089    }
090
091    @Override
092    public void run() {
093        DocumentModel versionDocument = session.getDocument(versionDocumentRef);
094        DocumentModel rendition = createRenditionDocument(versionDocument);
095        removeBlobs(rendition);
096        updateMainBlob(rendition);
097        updateIconAndSizeFields(rendition);
098
099        // create a copy of the doc
100        if(rendition.getId()==null) {
101            rendition = session.createDocument(rendition);
102        }
103        // be sure to have the same version info
104        setCorrectVersion(rendition, versionDocument);
105        // set ACL
106        // giveReadRightToUser(rendition);
107        // do not apply default versioning to rendition
108        rendition.putContextData(VersioningService.VERSIONING_OPTION, VersioningOption.NONE);
109        rendition = session.saveDocument(rendition);
110
111        // rendition is checkout : make it checkin
112        renditionRef = rendition.checkIn(VersioningOption.NONE, null);
113        rendition = session.getDocument(renditionRef);
114        session.save();
115
116        rendition.detach(true);
117        detachedDendition = rendition;
118    }
119
120    protected DocumentModel createRenditionDocument(DocumentModel versionDocument) {
121        String doctype = versionDocument.getType();
122        String renditionMimeType = renditionBlob.getMimeType();
123        if (versionDocument.getAdapter(BlobHolder.class) instanceof DocumentStringBlobHolder
124                && !(renditionMimeType.startsWith("text/") || renditionMimeType.startsWith("application/xhtml"))) {
125            // We have a Note or other blob holder that can only hold strings, but the rendition is not a string-related
126            // MIME type. We'll have to create a File instead to hold it.
127            doctype = FILE;
128        }
129
130        DocumentModel rendition=null;
131        DocumentModelList existingRenditions = session.query("select * from  " + doctype + " where ecm:isProxy = 0 AND ecm:mixinType ='"
132                + RENDITION_FACET + "' AND " + RENDITION_SOURCE_VERSIONABLE_ID_PROPERTY + "='" + liveDocumentId
133                + "' and " + RENDITION_NAME_PROPERTY + "='" + renditionName + "'");
134        if (existingRenditions.size() > 0) {
135            rendition = existingRenditions.get(0);
136            if (rendition.isVersion()) {
137                String sid = rendition.getVersionSeriesId();
138                rendition = session.getDocument(new IdRef(sid));
139            }
140        } else {
141            rendition = session.createDocumentModel(null, versionDocument.getName(), doctype);
142        }
143
144        rendition.copyContent(versionDocument);
145        rendition.getContextData().putScopedValue(LifeCycleConstants.INITIAL_LIFECYCLE_STATE_OPTION_NAME,
146                versionDocument.getCurrentLifeCycleState());
147
148        rendition.addFacet(RENDITION_FACET);
149        rendition.setPropertyValue(RENDITION_SOURCE_ID_PROPERTY, versionDocument.getId());
150        rendition.setPropertyValue(RENDITION_SOURCE_VERSIONABLE_ID_PROPERTY, liveDocumentId);
151        rendition.setPropertyValue(RENDITION_NAME_PROPERTY, renditionName);
152
153        return rendition;
154    }
155
156    protected void removeBlobs(DocumentModel rendition) {
157        if (rendition.hasSchema(FILES_SCHEMA)) {
158            rendition.setPropertyValue(FILES_FILES_PROPERTY, new ArrayList<Map<String, Serializable>>());
159        }
160    }
161
162    protected void updateMainBlob(DocumentModel rendition) {
163        BlobHolder bh = rendition.getAdapter(BlobHolder.class);
164        bh.setBlob(renditionBlob);
165    }
166
167    private void updateIconAndSizeFields(DocumentModel rendition) {
168        if (!rendition.hasSchema("common")) {
169            return;
170        }
171        MimetypeRegistry mimetypeService;
172        try {
173            mimetypeService = Framework.getService(MimetypeRegistry.class);
174        } catch (Exception e) {
175            log.error("Cannot fetch Mimetype service when updating icon and file size rendition", e);
176            return;
177        }
178        MimetypeEntry mimetypeEntry = mimetypeService.getMimetypeEntryByMimeType(renditionBlob.getMimeType());
179        if (mimetypeEntry != null && mimetypeEntry.getIconPath() != null) {
180            rendition.setPropertyValue("common:icon", "/icons/" + mimetypeEntry.getIconPath());
181        }
182        rendition.setPropertyValue("common:size", renditionBlob.getLength());
183    }
184
185    protected void giveReadRightToUser(DocumentModel rendition) {
186        ACP acp = new ACPImpl();
187        ACL acl = new ACLImpl();
188        acp.addACL(acl);
189        ACE ace = new ACE(getOriginatingUsername(), SecurityConstants.READ, true);
190        acl.add(ace);
191        rendition.setACP(acp, true);
192    }
193
194    protected void setCorrectVersion(DocumentModel rendition, DocumentModel versionDocument) {
195        Long minorVersion = (Long) versionDocument.getPropertyValue("uid:minor_version"); // -
196                                                                                          // 1L;
197        rendition.setPropertyValue("uid:minor_version", minorVersion);
198        rendition.setPropertyValue("uid:major_version", versionDocument.getPropertyValue("uid:major_version"));
199    }
200
201}