/** * * Copyright * 2009-2015 Jayway Products AB * 2016-2017 Föreningen Sambruk * * Licensed under AGPL, Version 3.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.gnu.org/licenses/agpl.txt * * 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. */ package se.streamsource.streamflow.web.management; import static org.qi4j.api.query.QueryExpressions.and; import static org.qi4j.api.query.QueryExpressions.isNotNull; import static org.qi4j.api.query.QueryExpressions.templateFor; import org.qi4j.api.cache.CacheOptions; import org.qi4j.api.injection.scope.Structure; import org.qi4j.api.query.Query; import org.qi4j.api.query.QueryBuilder; import org.qi4j.api.structure.Module; import org.qi4j.api.unitofwork.UnitOfWork; import org.qi4j.api.usecase.UsecaseBuilder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import se.streamsource.streamflow.web.domain.entity.caze.CaseEntity; import se.streamsource.streamflow.web.domain.structure.caselog.CaseLoggable; import se.streamsource.streamflow.web.domain.structure.caze.History; /** * Handles cleanup after update migration of history to case log. */ public class HistoryCleanup implements Runnable { @Structure Module module; Logger log = LoggerFactory.getLogger( HistoryCleanup.class ); private UnitOfWork findOldHistoryCases = null; private UnitOfWork deleteHistoryUow = null; private boolean stop = false; private long remaining = 0; public void run() { try { long historyToDeleteCount = 0; do { if( stop ) return; else { QueryBuilder<CaseEntity> queryBuilder = module.queryBuilderFactory().newQueryBuilder( CaseEntity.class ); findOldHistoryCases = module.unitOfWorkFactory().newUnitOfWork( UsecaseBuilder.buildUsecase( "FindOldHistoryCases" ).with( CacheOptions.NEVER ).newUsecase() ); Query<CaseEntity> query = queryBuilder.where( and( isNotNull( templateFor( History.Data.class ).history() ), isNotNull( templateFor( CaseLoggable.Data.class ).caselog() ) ) ) .newQuery( findOldHistoryCases ).maxResults( 1000 ); remaining = historyToDeleteCount = query.count(); int count = 0; for (CaseEntity caze : query) { if (stop) return; if (deleteHistoryUow == null) deleteHistoryUow = module.unitOfWorkFactory().newUnitOfWork( UsecaseBuilder.buildUsecase( "Upgrade_1.6.0.0_DeleteHistory" ).with( CacheOptions.NEVER ).newUsecase() ); if (caze != null && caze.history().get() != null) { CaseEntity caseToChange = deleteHistoryUow.get( caze ); caseToChange.history().get().deleteEntity(); caseToChange.history().set( null ); count++; remaining--; } if (count % 10 == 0) { log.info( " " + count + " old history entries about to be deleted." ); if( deleteHistoryUow != null ) deleteHistoryUow.complete(); deleteHistoryUow = null; log.info( "Delete succeded." ); synchronized (this) { this.wait( 500 ); } } } if (deleteHistoryUow != null) deleteHistoryUow.complete(); log.info( "Delete of " + count + " history entries done." ); log.info( +remaining + " remain for delete." ); } } while (historyToDeleteCount != 0 && !stop); findOldHistoryCases = null; log.info( "HistoryCleanup done." ); } catch (Throwable e) { log.error( e.getMessage() ); throw new RuntimeException( "Upgrade migration cleanup failed!", e ); } } public void stopAndDiscard() { stop = true; try { if (deleteHistoryUow != null) { deleteHistoryUow.discard(); deleteHistoryUow = null; } if (findOldHistoryCases != null) { findOldHistoryCases = null; } } catch (Throwable e) { log.error( "stopAndDiscard encountered problems.", e ); } log.info( "HistoryCleanup stopped and discarded with " + remaining + " cases left to cleanup." ); } }