001/* 002 * (C) Copyright 2018 Nuxeo (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 * Contributors: 017 * Kevin Leturc <kleturc@nuxeo.com> 018 */ 019package org.nuxeo.ecm.core.trash; 020 021import static org.nuxeo.ecm.core.query.sql.NXQL.ECM_UUID; 022import static org.nuxeo.ecm.core.trash.PropertyTrashService.SYSPROP_IS_TRASHED; 023 024import java.io.Serializable; 025import java.util.List; 026import java.util.Map; 027import java.util.stream.Collectors; 028 029import org.apache.commons.logging.Log; 030import org.apache.commons.logging.LogFactory; 031import org.nuxeo.ecm.core.api.CoreInstance; 032import org.nuxeo.ecm.core.api.CoreSession; 033import org.nuxeo.ecm.core.api.IdRef; 034import org.nuxeo.ecm.core.repository.RepositoryService; 035import org.nuxeo.runtime.api.Framework; 036import org.nuxeo.runtime.migration.MigrationService.MigrationContext; 037import org.nuxeo.runtime.migration.MigrationService.Migrator; 038import org.nuxeo.runtime.transaction.TransactionHelper; 039 040/** 041 * Migrator of trashed state from lifecycle to property. 042 * 043 * @since 10.2 044 */ 045public class TrashedStateLifeCycleToPropertyMigrator implements Migrator { 046 047 private static final Log log = LogFactory.getLog(TrashedStateLifeCycleToPropertyMigrator.class); 048 049 protected static final int BATCH_SIZE = 50; 050 051 protected MigrationContext migrationContext; 052 053 @Override 054 public void run(MigrationContext migrationContext) { 055 this.migrationContext = migrationContext; 056 reportProgress("Initializing", 0, -1); // unknown 057 List<String> repositoryNames = Framework.getService(RepositoryService.class).getRepositoryNames(); 058 try { 059 repositoryNames.forEach(this::migrateRepository); 060 reportProgress("Done", 1, 1); 061 } catch (MigrationShutdownException e) { 062 return; 063 } 064 } 065 066 protected void checkShutdownRequested() { 067 if (migrationContext.isShutdownRequested()) { 068 throw new MigrationShutdownException(); 069 } 070 } 071 072 protected void reportProgress(String message, long num, long total) { 073 log.debug(message + ": " + num + "/" + total); 074 migrationContext.reportProgress(message, num, total); 075 } 076 077 protected void reportProgress(String repositoryName, String message, long num, long total) { 078 reportProgress(String.format("[%s] %s", repositoryName, message), num, total); 079 } 080 081 protected void migrateRepository(String repositoryName) { 082 reportProgress(repositoryName, "Initializing", 0, -1); // unknown 083 TransactionHelper.runInTransaction(() -> CoreInstance.doPrivileged(repositoryName, this::migrateSession)); 084 } 085 086 protected void migrateSession(CoreSession session) { 087 // query all 'deleted' documents 088 String deletedQuery = "SELECT ecm:uuid FROM Document WHERE ecm:currentLifeCycleState = 'deleted' " 089 + "AND ecm:isVersion = 0"; 090 List<Map<String, Serializable>> deletedMaps = session.queryProjection(deletedQuery, -1, 0); 091 092 checkShutdownRequested(); 093 094 // compute all deleted doc id refs 095 List<IdRef> deletedRefs = deletedMaps.stream() // 096 .map(map -> (String) map.get(ECM_UUID)) 097 .map(IdRef::new) 098 .collect(Collectors.toList()); 099 100 checkShutdownRequested(); 101 102 // set ecm:isTrashed property by batch 103 int size = deletedRefs.size(); 104 int i = 0; 105 reportProgress(session.getRepositoryName(), "Setting isTrashed property", i, size); 106 for (IdRef deletedRef : deletedRefs) { 107 session.setDocumentSystemProp(deletedRef, SYSPROP_IS_TRASHED, Boolean.TRUE); 108 checkShutdownRequested(); 109 i++; 110 if (i % BATCH_SIZE == 0 || i == size) { 111 reportProgress(session.getRepositoryName(), "Setting isTrashed property", i, size); 112 TransactionHelper.commitOrRollbackTransaction(); 113 TransactionHelper.startTransaction(); 114 } 115 } 116 reportProgress(session.getRepositoryName(), "Done", size, size); 117 } 118 119 // exception used for simpler flow control 120 protected static class MigrationShutdownException extends RuntimeException { 121 122 private static final long serialVersionUID = 1L; 123 124 public MigrationShutdownException() { 125 super(); 126 } 127 } 128}