001/*
002 * This library is part of OpenCms -
003 * The Open Source Content Management System
004 *
005 * Copyright (c) Alkacon Software GmbH & Co. KG (https://www.alkacon.com)
006 *
007 * This library is free software; you can redistribute it and/or
008 * modify it under the terms of the GNU Lesser General Public
009 * License as published by the Free Software Foundation; either
010 * version 2.1 of the License, or (at your option) any later version.
011 */
012
013package org.opencms.ui.apps.cacheadmin;
014
015import org.opencms.file.CmsObject;
016import org.opencms.loader.CmsImageLoader;
017import org.opencms.loader.imagecache.CmsImageCacheMaintenanceCleaner;
018import org.opencms.loader.imagecache.CmsImageCacheMaintenanceService;
019import org.opencms.main.CmsLog;
020import org.opencms.main.OpenCms;
021import org.opencms.report.A_CmsReportThread;
022import org.opencms.report.I_CmsReport;
023import org.opencms.scheduler.jobs.CmsImageCacheCleanupJob;
024import org.opencms.ui.apps.Messages;
025
026import java.time.Instant;
027
028import org.apache.commons.logging.Log;
029
030/**
031 * Clears image cache entries in a report thread.<p>
032 */
033public class CmsImageCacheClearThread extends A_CmsReportThread {
034
035    /** Number of entries passed to one backend delete request. */
036    private static final int DELETE_BATCH_SIZE = 1000;
037
038    /** The logger. */
039    private static final Log LOG = CmsLog.getLog(CmsImageCacheClearThread.class);
040
041    /** The exclusive last-modified cutoff, or {@code null} for all entries. */
042    private final Instant m_cutoff;
043
044    /**
045     * Creates the report thread.<p>
046     *
047     * @param cms the current CMS context
048     * @param cutoff the exclusive last-modified cutoff, or {@code null} for all entries
049     */
050    public CmsImageCacheClearThread(CmsObject cms, Instant cutoff) {
051
052        super(cms, "imageCacheClear");
053        m_cutoff = cutoff;
054        initHtmlReport(cms.getRequestContext().getLocale());
055    }
056
057    /**
058     * @see org.opencms.report.A_CmsReportThread#getReportUpdate()
059     */
060    @Override
061    public String getReportUpdate() {
062
063        return getReport().getReportUpdate();
064    }
065
066    /**
067     * @see java.lang.Thread#run()
068     */
069    @Override
070    public void run() {
071
072        I_CmsReport report = getReport();
073        report.println(Messages.get().container(Messages.RPT_IMAGECACHE_CLEAR_BEGIN_0), I_CmsReport.FORMAT_HEADLINE);
074        try {
075            if (CmsImageLoader.getImageCache() == null) {
076                float maxAge = m_cutoff == null
077                ? -1f
078                : (System.currentTimeMillis() - m_cutoff.toEpochMilli()) / (60f * 60f * 1000f);
079                int deleted = CmsImageCacheCleanupJob.cleanImageCache(maxAge);
080                report.println(
081                    Messages.get().container(Messages.RPT_IMAGECACHE_CLEAR_END_3, 0, deleted, 0),
082                    I_CmsReport.FORMAT_OK);
083                return;
084            }
085            CmsImageCacheMaintenanceService service = CmsImageCacheMaintenanceService.createForConfiguredCache();
086            int deleteBatchSize = DELETE_BATCH_SIZE;
087            if ("s3".equals(service.getBackendId())) {
088                long concurrentBatchSize = (long)OpenCms.getImageCacheConfiguration().getS3DeleteBatchSize()
089                    * OpenCms.getImageCacheConfiguration().getS3DeleteConcurrency();
090                deleteBatchSize = (int)Math.min(Integer.MAX_VALUE, concurrentBatchSize);
091            }
092            CmsImageCacheMaintenanceCleaner.Result result = CmsImageCacheMaintenanceCleaner.delete(
093                service,
094                m_cutoff,
095                deleteBatchSize,
096                (progress, batch) -> {
097                    report.println(
098                        Messages.get().container(
099                            Messages.RPT_IMAGECACHE_CLEAR_PROGRESS_3,
100                            Long.valueOf(progress.getScanned()),
101                            Long.valueOf(progress.getMatched()),
102                            Long.valueOf(progress.getSucceeded())),
103                        batch.getFailed() == 0 ? I_CmsReport.FORMAT_DEFAULT : I_CmsReport.FORMAT_WARNING);
104                    for (Exception failure : batch.getFailures().values()) {
105                        report.println(failure);
106                    }
107                });
108            report.println(
109                Messages.get().container(
110                    Messages.RPT_IMAGECACHE_CLEAR_END_3,
111                    Long.valueOf(result.getScanned()),
112                    Long.valueOf(result.getSucceeded()),
113                    Long.valueOf(result.getFailed())),
114                result.getFailed() == 0 ? I_CmsReport.FORMAT_OK : I_CmsReport.FORMAT_WARNING);
115        } catch (Exception e) {
116            report.println(e);
117            LOG.error("Unable to clear the image cache.", e);
118        }
119    }
120}