/*
* (C) Copyright 2015-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:
* Thomas Roger
*/
package org.nuxeo.ecm.platform.picture;
import static org.apache.commons.logging.LogFactory.getLog;
import static org.nuxeo.ecm.core.api.CoreSession.ALLOW_VERSION_WRITE;
import static org.nuxeo.ecm.core.query.sql.NXQL.ECM_UUID;
import static org.nuxeo.ecm.core.query.sql.NXQL.NXQL;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.nuxeo.ecm.core.api.Blob;
import org.nuxeo.ecm.core.api.CoreSession;
import org.nuxeo.ecm.core.api.DocumentModel;
import org.nuxeo.ecm.core.api.IdRef;
import org.nuxeo.ecm.core.api.IterableQueryResult;
import org.nuxeo.ecm.core.repository.RepositoryInitializationHandler;
import org.nuxeo.ecm.platform.picture.api.PictureView;
import org.nuxeo.ecm.platform.picture.api.adapters.MultiviewPicture;
import org.nuxeo.runtime.api.Framework;
import org.nuxeo.runtime.services.config.ConfigurationService;
import org.nuxeo.runtime.transaction.TransactionHelper;
/**
* Migrate old Original picture view to {@code file:content}.
* <p>
* Does not copy it if {@code file:content} is not empty. When done, the Original picture view is removed.
* <p>
* It does not recompute the picture views.
*
* @since 7.2
*/
public class PictureMigrationHandler extends RepositoryInitializationHandler {
private static final Log log = getLog(PictureMigrationHandler.class);
public static final String PICTURES_TO_MIGRATE_QUERY = "SELECT ecm:uuid FROM Document "
+ "WHERE ecm:mixinType = 'Picture' AND ecm:isProxy = 0 AND views/*/title = 'Original' "
+ "AND content/data IS NULL";
public static final String ORIGINAL_VIEW_TITLE = "Original";
public static final String FILE_CONTENT_PROPERTY = "file:content";
public static final int BATCH_SIZE = 50;
public static final String DISABLE_QUOTA_CHECK_LISTENER = "disableQuotaListener";
@Override
public void doInitializeRepository(CoreSession session) {
if (Framework.getService(ConfigurationService.class).isBooleanPropertyTrue("nuxeo.picture.migration.enabled")) {
if (log.isInfoEnabled()) {
log.info(
"Starting picture migration handler (this may take some time depending on the number of documents)");
}
boolean txStarted = false;
if (!TransactionHelper.isTransactionActive()) {
txStarted = true;
}
try {
doMigration(session);
} finally {
if (txStarted) {
TransactionHelper.commitOrRollbackTransaction();
}
}
}
}
protected void doMigration(CoreSession session) {
Set<String> pictureIds = getPictureIdsToMigrate(session);
if (pictureIds.isEmpty()) {
return;
}
if (log.isInfoEnabled()) {
log.info(String.format("Started migration of %d documents with the 'Picture' facet", pictureIds.size()));
}
long pictureMigratedCount = 0;
try {
for (String pictureId : pictureIds) {
if (migratePicture(session, pictureId)) {
if (++pictureMigratedCount % BATCH_SIZE == 0) {
TransactionHelper.commitOrRollbackTransaction();
TransactionHelper.startTransaction();
}
}
}
} finally {
TransactionHelper.commitOrRollbackTransaction();
TransactionHelper.startTransaction();
}
if (log.isInfoEnabled()) {
log.info(String.format("Finished migration of %d/%d documents with the 'Picture' facet",
pictureMigratedCount, pictureIds.size()));
}
}
protected Set<String> getPictureIdsToMigrate(CoreSession session) {
IterableQueryResult it = null;
Set<String> pictureIds = new HashSet<>();
try {
it = session.queryAndFetch(PICTURES_TO_MIGRATE_QUERY, NXQL);
for (Map<String, Serializable> map : it) {
String id = (String) map.get(ECM_UUID);
if (id != null) {
pictureIds.add(id);
}
}
} finally {
if (it != null) {
it.close();
}
}
return pictureIds;
}
protected boolean migratePicture(CoreSession session, String docId) {
DocumentModel picture = session.getDocument(new IdRef(docId));
if (log.isDebugEnabled()) {
log.debug(String.format("Migrating %s", picture));
}
MultiviewPicture multiviewPicture = picture.getAdapter(MultiviewPicture.class);
PictureView originalView = multiviewPicture.getView(ORIGINAL_VIEW_TITLE);
Blob blob = originalView.getBlob();
if (blob == null) {
if (log.isWarnEnabled()) {
log.warn(String.format("No Original view Blob found for %s", picture));
}
return false;
}
String filename = blob.getFilename();
filename = StringUtils.defaultString(filename).replaceAll("^Original_", "");
blob.setFilename(filename);
picture.setPropertyValue(FILE_CONTENT_PROPERTY, (Serializable) blob);
multiviewPicture.removeView(ORIGINAL_VIEW_TITLE);
if (picture.isVersion()) {
picture.putContextData(ALLOW_VERSION_WRITE, Boolean.TRUE);
}
// disable quota if installed
picture.putContextData(DISABLE_QUOTA_CHECK_LISTENER, Boolean.TRUE);
session.saveDocument(picture);
return true;
}
}