/*
* (C) Copyright 2010-2016 Nuxeo SA (http://nuxeo.com/) and others.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Contributors:
* Nuxeo - initial API and implementation
*/
package org.nuxeo.ecm.platform.rendition.service;
import static org.nuxeo.ecm.platform.rendition.Constants.FILES_FILES_PROPERTY;
import static org.nuxeo.ecm.platform.rendition.Constants.FILES_SCHEMA;
import static org.nuxeo.ecm.platform.rendition.Constants.RENDITION_FACET;
import static org.nuxeo.ecm.platform.rendition.Constants.RENDITION_NAME_PROPERTY;
import static org.nuxeo.ecm.platform.rendition.Constants.RENDITION_SOURCE_ID_PROPERTY;
import static org.nuxeo.ecm.platform.rendition.Constants.RENDITION_SOURCE_MODIFICATION_DATE_PROPERTY;
import static org.nuxeo.ecm.platform.rendition.Constants.RENDITION_SOURCE_VERSIONABLE_ID_PROPERTY;
import static org.nuxeo.ecm.platform.rendition.Constants.RENDITION_VARIANT_PROPERTY;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.nuxeo.ecm.core.api.Blob;
import org.nuxeo.ecm.core.api.DocumentModel;
import org.nuxeo.ecm.core.api.DocumentModelList;
import org.nuxeo.ecm.core.api.DocumentRef;
import org.nuxeo.ecm.core.api.IdRef;
import org.nuxeo.ecm.core.api.LifeCycleConstants;
import org.nuxeo.ecm.core.api.UnrestrictedSessionRunner;
import org.nuxeo.ecm.core.api.VersioningOption;
import org.nuxeo.ecm.core.api.blobholder.BlobHolder;
import org.nuxeo.ecm.core.api.blobholder.DocumentStringBlobHolder;
import org.nuxeo.ecm.core.query.sql.NXQL;
import org.nuxeo.ecm.core.versioning.VersioningService;
import org.nuxeo.ecm.platform.mimetype.interfaces.MimetypeEntry;
import org.nuxeo.ecm.platform.mimetype.interfaces.MimetypeRegistry;
import org.nuxeo.runtime.api.Framework;
/**
* @author <a href="mailto:troger@nuxeo.com">Thomas Roger</a>
*/
public class RenditionCreator extends UnrestrictedSessionRunner {
private static final Log log = LogFactory.getLog(RenditionCreator.class);
public static final String FILE = "File";
protected DocumentModel detachedRendition;
protected String liveDocumentId;
protected String versionDocumentId;
protected Blob renditionBlob;
protected String renditionName;
/**
* @since 8.1
*/
protected RenditionDefinition renditionDefinition;
/**
* @since 8.1
*/
protected final String renditionVariant;
/**
* @since 8.1
*/
public RenditionCreator(DocumentModel liveDocument, DocumentModel versionDocument, Blob renditionBlob,
RenditionDefinition renditionDefinition) {
super(liveDocument.getCoreSession());
liveDocumentId = liveDocument.getId();
versionDocumentId = versionDocument == null ? null : versionDocument.getId();
this.renditionBlob = renditionBlob;
this.renditionDefinition = renditionDefinition;
renditionName = renditionDefinition.getName();
renditionVariant = renditionDefinition.getProvider().getVariant(liveDocument, renditionDefinition);
}
public DocumentModel getDetachedRendition() {
return detachedRendition;
}
/**
* @deprecated since 7.10, misspelled, use {@link #getDetachedRendition} instead.
*/
@Deprecated
public DocumentModel getDetachedDendition() {
return detachedRendition;
}
@Override
public void run() {
DocumentModel liveDocument = session.getDocument(new IdRef(liveDocumentId));
DocumentModel sourceDocument = liveDocument.isVersionable() ? session.getDocument(new IdRef(versionDocumentId))
: liveDocument;
DocumentModel rendition = createRenditionDocument(sourceDocument);
removeBlobs(rendition);
updateMainBlob(rendition);
updateIconField(rendition);
// create a copy of the doc
if (rendition.getId() == null) {
rendition = session.createDocument(rendition);
}
if (sourceDocument.isVersionable()) {
// be sure to have the same version info
setCorrectVersion(rendition, sourceDocument);
}
// do not apply default versioning to rendition
rendition.putContextData(VersioningService.VERSIONING_OPTION, VersioningOption.NONE);
rendition = session.saveDocument(rendition);
if (sourceDocument.isVersionable()) {
// rendition is checked out: check it in
DocumentRef renditionRef = rendition.checkIn(VersioningOption.NONE, null);
rendition = session.getDocument(renditionRef);
}
session.save();
rendition.detach(true);
detachedRendition = rendition;
}
protected DocumentModel createRenditionDocument(DocumentModel sourceDocument) {
String doctype = sourceDocument.getType();
String renditionMimeType = renditionBlob.getMimeType();
BlobHolder blobHolder = sourceDocument.getAdapter(BlobHolder.class);
if (blobHolder == null || (blobHolder instanceof DocumentStringBlobHolder
&& !(renditionMimeType.startsWith("text/") || renditionMimeType.startsWith("application/xhtml")))) {
// We have a document type unable to hold blobs, or
// We have a Note or other blob holder that can only hold strings, but the rendition is not a string-related
// MIME type.
// In either case, we'll have to create a File to hold it.
doctype = FILE;
}
boolean isVersionable = sourceDocument.isVersionable();
String liveDocProp = isVersionable ? RENDITION_SOURCE_VERSIONABLE_ID_PROPERTY : RENDITION_SOURCE_ID_PROPERTY;
StringBuilder query = new StringBuilder();
query.append("SELECT * FROM Document WHERE ecm:isProxy = 0 AND ");
query.append(RENDITION_NAME_PROPERTY);
query.append(" = '");
query.append(NXQL.escapeStringInner(renditionName));
query.append("' AND ");
if (renditionVariant != null) {
query.append(RENDITION_VARIANT_PROPERTY);
query.append(" = '");
query.append(NXQL.escapeStringInner(renditionVariant));
query.append("' AND ");
}
query.append(liveDocProp);
query.append(" = '");
query.append(liveDocumentId);
query.append("'");
DocumentModelList existingRenditions = session.query(query.toString());
String modificationDatePropertyName = getSourceDocumentModificationDatePropertyName();
Calendar sourceLastModified = (Calendar) sourceDocument.getPropertyValue(modificationDatePropertyName);
DocumentModel rendition;
if (existingRenditions.size() > 0) {
rendition = session.getDocument(existingRenditions.get(0).getRef());
if (!isVersionable) {
Calendar renditionSourceLastModified = (Calendar) rendition.getPropertyValue(
RENDITION_SOURCE_MODIFICATION_DATE_PROPERTY);
if (renditionSourceLastModified != null && !renditionSourceLastModified.before(sourceLastModified)) {
this.renditionBlob = (Blob) rendition.getPropertyValue("file:content");
return rendition;
}
}
if (rendition.isVersion()) {
String sid = rendition.getVersionSeriesId();
rendition = session.getDocument(new IdRef(sid));
}
} else {
rendition = session.createDocumentModel(null, sourceDocument.getName(), doctype);
}
rendition.copyContent(sourceDocument);
rendition.putContextData(LifeCycleConstants.INITIAL_LIFECYCLE_STATE_OPTION_NAME,
sourceDocument.getCurrentLifeCycleState());
rendition.addFacet(RENDITION_FACET);
rendition.setPropertyValue(RENDITION_SOURCE_ID_PROPERTY, sourceDocument.getId());
if (isVersionable) {
rendition.setPropertyValue(RENDITION_SOURCE_VERSIONABLE_ID_PROPERTY, liveDocumentId);
}
if (sourceLastModified != null) {
rendition.setPropertyValue(RENDITION_SOURCE_MODIFICATION_DATE_PROPERTY, sourceLastModified);
}
if (renditionVariant != null) {
rendition.setPropertyValue(RENDITION_VARIANT_PROPERTY, renditionVariant);
}
rendition.setPropertyValue(RENDITION_NAME_PROPERTY, renditionName);
return rendition;
}
protected void removeBlobs(DocumentModel rendition) {
if (rendition.hasSchema(FILES_SCHEMA)) {
rendition.setPropertyValue(FILES_FILES_PROPERTY, new ArrayList<Map<String, Serializable>>());
}
}
protected void updateMainBlob(DocumentModel rendition) {
BlobHolder bh = rendition.getAdapter(BlobHolder.class);
bh.setBlob(renditionBlob);
}
private void updateIconField(DocumentModel rendition) {
if (!rendition.hasSchema("common")) {
return;
}
MimetypeRegistry mimetypeService;
try {
mimetypeService = Framework.getService(MimetypeRegistry.class);
} catch (Exception e) {
log.error("Cannot fetch Mimetype service when updating icon and file size rendition", e);
return;
}
MimetypeEntry mimetypeEntry = mimetypeService.getMimetypeEntryByMimeType(renditionBlob.getMimeType());
if (mimetypeEntry != null && mimetypeEntry.getIconPath() != null) {
rendition.setPropertyValue("common:icon", "/icons/" + mimetypeEntry.getIconPath());
}
}
protected void setCorrectVersion(DocumentModel rendition, DocumentModel versionDocument) {
Long minorVersion = (Long) versionDocument.getPropertyValue("uid:minor_version");
rendition.setPropertyValue("uid:minor_version", minorVersion);
rendition.setPropertyValue("uid:major_version", versionDocument.getPropertyValue("uid:major_version"));
}
protected String getSourceDocumentModificationDatePropertyName() {
return renditionDefinition.getSourceDocumentModificationDatePropertyName();
}
}